changeset 17:75e5bb1e0aa1

going to now integrate the gb src tree since it has no dependencies
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 11:44:47 -0600
parents 9e598342e182
children ac56489c2ca6
files src/gb/GB.cpp src/gb/GB.h src/gb/Makefile.am src/gb/gbCheats.cpp src/gb/gbCheats.h src/gb/gbCodes.h src/gb/gbCodesCB.h src/gb/gbDis.cpp src/gb/gbGfx.cpp src/gb/gbGlobals.cpp src/gb/gbGlobals.h src/gb/gbMemory.cpp src/gb/gbMemory.h src/gb/gbPrinter.cpp src/gb/gbPrinter.h src/gb/gbSGB.cpp src/gb/gbSGB.h src/gb/gbSound.cpp src/gb/gbSound.h
diffstat 19 files changed, 11765 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/gb/GB.cpp	Sat Mar 03 11:44:47 2012 -0600
     1.3 @@ -0,0 +1,3918 @@
     1.4 +#include <cstdio>
     1.5 +#include <cstdlib>
     1.6 +#include <cstring>
     1.7 +#include <cassert>
     1.8 +
     1.9 +#include "../Port.h"
    1.10 +#include "../NLS.h"
    1.11 +#include "GB.h"
    1.12 +#include "gbCheats.h"
    1.13 +#include "gbGlobals.h"
    1.14 +#include "gbMemory.h"
    1.15 +#include "gbSGB.h"
    1.16 +#include "gbSound.h"
    1.17 +#include "../common/unzip.h"
    1.18 +#include "../common/Util.h"
    1.19 +#include "../common/System.h"
    1.20 +#include "../common/movie.h"
    1.21 +#include "../common/vbalua.h"
    1.22 +
    1.23 +#ifdef __GNUC__
    1.24 +#define _stricmp strcasecmp
    1.25 +#endif
    1.26 +
    1.27 +// FIXME: constant (GB) or boolean (GBA)?!
    1.28 +#define C_FLAG 0x10
    1.29 +#define H_FLAG 0x20
    1.30 +#define N_FLAG 0x40
    1.31 +#define Z_FLAG 0x80
    1.32 +extern soundtick_t GB_USE_TICKS_AS;
    1.33 +
    1.34 +u8 *		 origPix = NULL;
    1.35 +extern u8 *	 pix;
    1.36 +extern u32	 extButtons;
    1.37 +extern bool8 capturePrevious;
    1.38 +extern int32 captureNumber;
    1.39 +extern bool8 speedup;
    1.40 +
    1.41 +bool gbUpdateSizes();
    1.42 +
    1.43 +// debugging
    1.44 +bool memorydebug = false;
    1.45 +char gbBuffer[2048];
    1.46 +
    1.47 +extern u16 gbLineMix[160];
    1.48 +
    1.49 +// mappers
    1.50 +void (*mapper)(u16, u8)	   = NULL;
    1.51 +void (*mapperRAM)(u16, u8) = NULL;
    1.52 +u8	 (*mapperReadRAM)(u16) = NULL;
    1.53 +
    1.54 +// registers
    1.55 +gbRegister PC;
    1.56 +gbRegister SP;
    1.57 +gbRegister AF;
    1.58 +gbRegister BC;
    1.59 +gbRegister DE;
    1.60 +gbRegister HL;
    1.61 +u16		   IFF;
    1.62 +// 0xff04
    1.63 +u8 register_DIV = 0;
    1.64 +// 0xff05
    1.65 +u8 register_TIMA = 0;
    1.66 +// 0xff06
    1.67 +u8 register_TMA = 0;
    1.68 +// 0xff07
    1.69 +u8 register_TAC = 0;
    1.70 +// 0xff0f
    1.71 +u8 register_IF = 0;
    1.72 +// 0xff40
    1.73 +u8 register_LCDC = 0;
    1.74 +// 0xff41
    1.75 +u8 register_STAT = 0;
    1.76 +// 0xff42
    1.77 +u8 register_SCY = 0;
    1.78 +// 0xff43
    1.79 +u8 register_SCX = 0;
    1.80 +// 0xff44
    1.81 +u8 register_LY = 0;
    1.82 +// 0xff45
    1.83 +u8 register_LYC = 0;
    1.84 +// 0xff46
    1.85 +u8 register_DMA = 0;
    1.86 +// 0xff4a
    1.87 +u8 register_WY = 0;
    1.88 +// 0xff4b
    1.89 +u8 register_WX = 0;
    1.90 +// 0xff4f
    1.91 +u8 register_VBK = 0;
    1.92 +// 0xff51
    1.93 +u8 register_HDMA1 = 0;
    1.94 +// 0xff52
    1.95 +u8 register_HDMA2 = 0;
    1.96 +// 0xff53
    1.97 +u8 register_HDMA3 = 0;
    1.98 +// 0xff54
    1.99 +u8 register_HDMA4 = 0;
   1.100 +// 0xff55
   1.101 +u8 register_HDMA5 = 0;
   1.102 +// 0xff70
   1.103 +u8 register_SVBK = 0;
   1.104 +// 0xffff
   1.105 +u8 register_IE = 0;
   1.106 +
   1.107 +// ticks definition
   1.108 +int32 GBDIV_CLOCK_TICKS = 64;
   1.109 +int32 GBLCD_MODE_0_CLOCK_TICKS	 = 51;
   1.110 +int32 GBLCD_MODE_1_CLOCK_TICKS	 = 1140;
   1.111 +int32 GBLCD_MODE_2_CLOCK_TICKS	 = 20;
   1.112 +int32 GBLCD_MODE_3_CLOCK_TICKS	 = 43;
   1.113 +int32 GBLY_INCREMENT_CLOCK_TICKS = 114;
   1.114 +int32 GBTIMER_MODE_0_CLOCK_TICKS = 256;
   1.115 +int32 GBTIMER_MODE_1_CLOCK_TICKS = 4;
   1.116 +int32 GBTIMER_MODE_2_CLOCK_TICKS = 16;
   1.117 +int32 GBTIMER_MODE_3_CLOCK_TICKS = 64;
   1.118 +int32 GBSERIAL_CLOCK_TICKS		 = 128;
   1.119 +int32 GBSYNCHRONIZE_CLOCK_TICKS	 = 52920;
   1.120 +
   1.121 +// state variables
   1.122 +
   1.123 +// interrupt
   1.124 +int32 gbInterrupt	  = 0;
   1.125 +int32 gbInterruptWait = 0;
   1.126 +// serial
   1.127 +int32 gbSerialOn	= 0;
   1.128 +int32 gbSerialTicks = 0;
   1.129 +int32 gbSerialBits	= 0;
   1.130 +// timer
   1.131 +int32 gbTimerOn			= 0;
   1.132 +int32 gbTimerTicks		= 0;
   1.133 +int32 gbTimerClockTicks = 0;
   1.134 +int32 gbTimerMode		= 0;
   1.135 +// lcd
   1.136 +int32 gbLcdMode	 = 2;
   1.137 +int32 gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS;
   1.138 +int32 gbLcdLYIncrementTicks = 0;
   1.139 +// div
   1.140 +int32 gbDivTicks = GBDIV_CLOCK_TICKS;
   1.141 +// cgb
   1.142 +int32 gbVramBank		= 0;
   1.143 +int32 gbWramBank		= 1;
   1.144 +int32 gbHdmaSource		= 0x0000;
   1.145 +int32 gbHdmaDestination = 0x8000;
   1.146 +int32 gbHdmaBytes		= 0x0000;
   1.147 +int32 gbHdmaOn = 0;
   1.148 +int32 gbSpeed  = 0;
   1.149 +// frame counting
   1.150 +int32 gbFrameCount	   = 0;
   1.151 +int32 gbFrameSkip	   = 0;
   1.152 +int32 gbFrameSkipCount = 0;
   1.153 +// timing
   1.154 +u32	  gbLastTime		 = 0;
   1.155 +u32	  gbElapsedTime		 = 0;
   1.156 +u32	  gbTimeNow			 = 0;
   1.157 +int32 gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS;
   1.158 +int32 gbDMASpeedVersion	 = 1;
   1.159 +// emulator features
   1.160 +int32 gbBattery	   = 0;
   1.161 +int32 gbJoymask[4] = { 0, 0, 0, 0 };
   1.162 +
   1.163 +int32 gbEchoRAMFixOn = 1;
   1.164 +
   1.165 +static bool newFrame = true;
   1.166 +static bool pauseAfterFrameAdvance = false;
   1.167 +
   1.168 +int32 gbRomSizes[] = { 0x00008000, // 32K
   1.169 +	                   0x00010000, // 64K
   1.170 +	                   0x00020000, // 128K
   1.171 +	                   0x00040000, // 256K
   1.172 +	                   0x00080000, // 512K
   1.173 +	                   0x00100000, // 1024K
   1.174 +	                   0x00200000, // 2048K
   1.175 +	                   0x00400000, // 4096K
   1.176 +	                   0x00800000 // 8192K
   1.177 +};
   1.178 +int32 gbRomSizesMasks[] = { 0x00007fff,
   1.179 +	                        0x0000ffff,
   1.180 +	                        0x0001ffff,
   1.181 +	                        0x0003ffff,
   1.182 +	                        0x0007ffff,
   1.183 +	                        0x000fffff,
   1.184 +	                        0x001fffff,
   1.185 +	                        0x003fffff,
   1.186 +	                        0x007fffff };
   1.187 +
   1.188 +int32 gbRamSizes[6] = { 0x00000000, // 0K
   1.189 +	                    0x00000800, // 2K
   1.190 +	                    0x00002000, // 8K
   1.191 +	                    0x00008000, // 32K
   1.192 +	                    0x00020000, // 128K
   1.193 +	                    0x00010000 // 64K
   1.194 +};
   1.195 +
   1.196 +int32 gbRamSizesMasks[6] = { 0x00000000,
   1.197 +	                         0x000007ff,
   1.198 +	                         0x00001fff,
   1.199 +	                         0x00007fff,
   1.200 +	                         0x0001ffff,
   1.201 +	                         0x0000ffff };
   1.202 +
   1.203 +int32 gbCycles[] =
   1.204 +{
   1.205 +//  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
   1.206 +	1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1,  // 0
   1.207 +	1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1,  // 1
   1.208 +	2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1,  // 2
   1.209 +	2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1,  // 3
   1.210 +	1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,  // 4
   1.211 +	1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,  // 5
   1.212 +	1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,  // 6
   1.213 +	2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1,  // 7
   1.214 +	1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,  // 8
   1.215 +	1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,  // 9
   1.216 +	1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,  // a
   1.217 +	1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,  // b
   1.218 +	2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4,  // c
   1.219 +	2, 3, 3, 0, 3, 4, 2, 4, 2, 4, 3, 0, 3, 0, 2, 4,  // d
   1.220 +	3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4,  // e
   1.221 +	3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4   // f
   1.222 +};
   1.223 +
   1.224 +int32 gbCyclesCB[] =
   1.225 +{
   1.226 +//  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
   1.227 +	2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,  // 0
   1.228 +	2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,  // 1
   1.229 +	2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,  // 2
   1.230 +	2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,  // 3
   1.231 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // 4
   1.232 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // 5
   1.233 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // 6
   1.234 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // 7
   1.235 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // 8
   1.236 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // 9
   1.237 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // a
   1.238 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // b
   1.239 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // c
   1.240 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // d
   1.241 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,  // e
   1.242 +	2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2   // f
   1.243 +};
   1.244 +
   1.245 +u16 DAATable[] =
   1.246 +{
   1.247 +	0x0080, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700,
   1.248 +	0x0800, 0x0900, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520,
   1.249 +	0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700,
   1.250 +	0x1800, 0x1900, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520,
   1.251 +	0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700,
   1.252 +	0x2800, 0x2900, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520,
   1.253 +	0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700,
   1.254 +	0x3800, 0x3900, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520,
   1.255 +	0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700,
   1.256 +	0x4800, 0x4900, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520,
   1.257 +	0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700,
   1.258 +	0x5800, 0x5900, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520,
   1.259 +	0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, 0x6700,
   1.260 +	0x6800, 0x6900, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520,
   1.261 +	0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700,
   1.262 +	0x7800, 0x7900, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520,
   1.263 +	0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700,
   1.264 +	0x8800, 0x8900, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520,
   1.265 +	0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700,
   1.266 +	0x9800, 0x9900, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530,
   1.267 +	0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710,
   1.268 +	0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530,
   1.269 +	0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710,
   1.270 +	0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530,
   1.271 +	0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710,
   1.272 +	0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530,
   1.273 +	0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710,
   1.274 +	0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530,
   1.275 +	0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710,
   1.276 +	0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530,
   1.277 +	0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710,
   1.278 +	0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530,
   1.279 +	0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, 0x6610, 0x6710,
   1.280 +	0x6810, 0x6910, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530,
   1.281 +	0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, 0x7610, 0x7710,
   1.282 +	0x7810, 0x7910, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530,
   1.283 +	0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, 0x8610, 0x8710,
   1.284 +	0x8810, 0x8910, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530,
   1.285 +	0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, 0x9610, 0x9710,
   1.286 +	0x9810, 0x9910, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530,
   1.287 +	0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, 0xA610, 0xA710,
   1.288 +	0xA810, 0xA910, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530,
   1.289 +	0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, 0xB610, 0xB710,
   1.290 +	0xB810, 0xB910, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530,
   1.291 +	0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, 0xC610, 0xC710,
   1.292 +	0xC810, 0xC910, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530,
   1.293 +	0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, 0xD610, 0xD710,
   1.294 +	0xD810, 0xD910, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530,
   1.295 +	0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, 0xE610, 0xE710,
   1.296 +	0xE810, 0xE910, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530,
   1.297 +	0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, 0xF610, 0xF710,
   1.298 +	0xF810, 0xF910, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530,
   1.299 +	0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710,
   1.300 +	0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530,
   1.301 +	0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710,
   1.302 +	0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530,
   1.303 +	0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710,
   1.304 +	0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530,
   1.305 +	0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710,
   1.306 +	0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530,
   1.307 +	0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710,
   1.308 +	0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530,
   1.309 +	0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710,
   1.310 +	0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530,
   1.311 +	0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00,
   1.312 +	0x0E00, 0x0F00, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520,
   1.313 +	0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00,
   1.314 +	0x1E00, 0x1F00, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520,
   1.315 +	0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00,
   1.316 +	0x2E00, 0x2F00, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520,
   1.317 +	0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00,
   1.318 +	0x3E00, 0x3F00, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520,
   1.319 +	0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00,
   1.320 +	0x4E00, 0x4F00, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520,
   1.321 +	0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00,
   1.322 +	0x5E00, 0x5F00, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520,
   1.323 +	0x6600, 0x6700, 0x6800, 0x6900, 0x6A00, 0x6B00, 0x6C00, 0x6D00,
   1.324 +	0x6E00, 0x6F00, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520,
   1.325 +	0x7600, 0x7700, 0x7800, 0x7900, 0x7A00, 0x7B00, 0x7C00, 0x7D00,
   1.326 +	0x7E00, 0x7F00, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520,
   1.327 +	0x8600, 0x8700, 0x8800, 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x8D00,
   1.328 +	0x8E00, 0x8F00, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520,
   1.329 +	0x9600, 0x9700, 0x9800, 0x9900, 0x9A00, 0x9B00, 0x9C00, 0x9D00,
   1.330 +	0x9E00, 0x9F00, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530,
   1.331 +	0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10,
   1.332 +	0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530,
   1.333 +	0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10,
   1.334 +	0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530,
   1.335 +	0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10,
   1.336 +	0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530,
   1.337 +	0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10,
   1.338 +	0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530,
   1.339 +	0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10,
   1.340 +	0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530,
   1.341 +	0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10,
   1.342 +	0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530,
   1.343 +	0x6610, 0x6710, 0x6810, 0x6910, 0x6A10, 0x6B10, 0x6C10, 0x6D10,
   1.344 +	0x6E10, 0x6F10, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530,
   1.345 +	0x7610, 0x7710, 0x7810, 0x7910, 0x7A10, 0x7B10, 0x7C10, 0x7D10,
   1.346 +	0x7E10, 0x7F10, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530,
   1.347 +	0x8610, 0x8710, 0x8810, 0x8910, 0x8A10, 0x8B10, 0x8C10, 0x8D10,
   1.348 +	0x8E10, 0x8F10, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530,
   1.349 +	0x9610, 0x9710, 0x9810, 0x9910, 0x9A10, 0x9B10, 0x9C10, 0x9D10,
   1.350 +	0x9E10, 0x9F10, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530,
   1.351 +	0xA610, 0xA710, 0xA810, 0xA910, 0xAA10, 0xAB10, 0xAC10, 0xAD10,
   1.352 +	0xAE10, 0xAF10, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530,
   1.353 +	0xB610, 0xB710, 0xB810, 0xB910, 0xBA10, 0xBB10, 0xBC10, 0xBD10,
   1.354 +	0xBE10, 0xBF10, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530,
   1.355 +	0xC610, 0xC710, 0xC810, 0xC910, 0xCA10, 0xCB10, 0xCC10, 0xCD10,
   1.356 +	0xCE10, 0xCF10, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530,
   1.357 +	0xD610, 0xD710, 0xD810, 0xD910, 0xDA10, 0xDB10, 0xDC10, 0xDD10,
   1.358 +	0xDE10, 0xDF10, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530,
   1.359 +	0xE610, 0xE710, 0xE810, 0xE910, 0xEA10, 0xEB10, 0xEC10, 0xED10,
   1.360 +	0xEE10, 0xEF10, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530,
   1.361 +	0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, 0xFC10, 0xFD10,
   1.362 +	0xFE10, 0xFF10, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530,
   1.363 +	0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10,
   1.364 +	0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530,
   1.365 +	0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10,
   1.366 +	0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530,
   1.367 +	0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10,
   1.368 +	0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530,
   1.369 +	0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10,
   1.370 +	0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530,
   1.371 +	0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10,
   1.372 +	0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530,
   1.373 +	0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10,
   1.374 +	0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530,
   1.375 +	0x00C0, 0x0140, 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740,
   1.376 +	0x0840, 0x0940, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940,
   1.377 +	0x1040, 0x1140, 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740,
   1.378 +	0x1840, 0x1940, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940,
   1.379 +	0x2040, 0x2140, 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740,
   1.380 +	0x2840, 0x2940, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940,
   1.381 +	0x3040, 0x3140, 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740,
   1.382 +	0x3840, 0x3940, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940,
   1.383 +	0x4040, 0x4140, 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740,
   1.384 +	0x4840, 0x4940, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940,
   1.385 +	0x5040, 0x5140, 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740,
   1.386 +	0x5840, 0x5940, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940,
   1.387 +	0x6040, 0x6140, 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740,
   1.388 +	0x6840, 0x6940, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940,
   1.389 +	0x7040, 0x7140, 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740,
   1.390 +	0x7840, 0x7940, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940,
   1.391 +	0x8040, 0x8140, 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740,
   1.392 +	0x8840, 0x8940, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940,
   1.393 +	0x9040, 0x9140, 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740,
   1.394 +	0x9840, 0x9940, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950,
   1.395 +	0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750,
   1.396 +	0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950,
   1.397 +	0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750,
   1.398 +	0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950,
   1.399 +	0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750,
   1.400 +	0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950,
   1.401 +	0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750,
   1.402 +	0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950,
   1.403 +	0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750,
   1.404 +	0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950,
   1.405 +	0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750,
   1.406 +	0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950,
   1.407 +	0xA050, 0xA150, 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750,
   1.408 +	0xA850, 0xA950, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950,
   1.409 +	0xB050, 0xB150, 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750,
   1.410 +	0xB850, 0xB950, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950,
   1.411 +	0xC050, 0xC150, 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750,
   1.412 +	0xC850, 0xC950, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950,
   1.413 +	0xD050, 0xD150, 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750,
   1.414 +	0xD850, 0xD950, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950,
   1.415 +	0xE050, 0xE150, 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750,
   1.416 +	0xE850, 0xE950, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950,
   1.417 +	0xF050, 0xF150, 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750,
   1.418 +	0xF850, 0xF950, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950,
   1.419 +	0x00D0, 0x0150, 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750,
   1.420 +	0x0850, 0x0950, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950,
   1.421 +	0x1050, 0x1150, 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750,
   1.422 +	0x1850, 0x1950, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950,
   1.423 +	0x2050, 0x2150, 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750,
   1.424 +	0x2850, 0x2950, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950,
   1.425 +	0x3050, 0x3150, 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750,
   1.426 +	0x3850, 0x3950, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950,
   1.427 +	0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750,
   1.428 +	0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950,
   1.429 +	0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750,
   1.430 +	0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950,
   1.431 +	0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750,
   1.432 +	0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950,
   1.433 +	0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750,
   1.434 +	0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950,
   1.435 +	0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750,
   1.436 +	0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950,
   1.437 +	0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750,
   1.438 +	0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950,
   1.439 +	0xFA60, 0xFB60, 0xFC60, 0xFD60, 0xFE60, 0xFF60, 0x00C0, 0x0140,
   1.440 +	0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940,
   1.441 +	0x0A60, 0x0B60, 0x0C60, 0x0D60, 0x0E60, 0x0F60, 0x1040, 0x1140,
   1.442 +	0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940,
   1.443 +	0x1A60, 0x1B60, 0x1C60, 0x1D60, 0x1E60, 0x1F60, 0x2040, 0x2140,
   1.444 +	0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940,
   1.445 +	0x2A60, 0x2B60, 0x2C60, 0x2D60, 0x2E60, 0x2F60, 0x3040, 0x3140,
   1.446 +	0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940,
   1.447 +	0x3A60, 0x3B60, 0x3C60, 0x3D60, 0x3E60, 0x3F60, 0x4040, 0x4140,
   1.448 +	0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940,
   1.449 +	0x4A60, 0x4B60, 0x4C60, 0x4D60, 0x4E60, 0x4F60, 0x5040, 0x5140,
   1.450 +	0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940,
   1.451 +	0x5A60, 0x5B60, 0x5C60, 0x5D60, 0x5E60, 0x5F60, 0x6040, 0x6140,
   1.452 +	0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940,
   1.453 +	0x6A60, 0x6B60, 0x6C60, 0x6D60, 0x6E60, 0x6F60, 0x7040, 0x7140,
   1.454 +	0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940,
   1.455 +	0x7A60, 0x7B60, 0x7C60, 0x7D60, 0x7E60, 0x7F60, 0x8040, 0x8140,
   1.456 +	0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940,
   1.457 +	0x8A60, 0x8B60, 0x8C60, 0x8D60, 0x8E60, 0x8F60, 0x9040, 0x9140,
   1.458 +	0x9240, 0x9340, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950,
   1.459 +	0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150,
   1.460 +	0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950,
   1.461 +	0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150,
   1.462 +	0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950,
   1.463 +	0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150,
   1.464 +	0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950,
   1.465 +	0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150,
   1.466 +	0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950,
   1.467 +	0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150,
   1.468 +	0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950,
   1.469 +	0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150,
   1.470 +	0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950,
   1.471 +	0x9A70, 0x9B70, 0x9C70, 0x9D70, 0x9E70, 0x9F70, 0xA050, 0xA150,
   1.472 +	0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950,
   1.473 +	0xAA70, 0xAB70, 0xAC70, 0xAD70, 0xAE70, 0xAF70, 0xB050, 0xB150,
   1.474 +	0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950,
   1.475 +	0xBA70, 0xBB70, 0xBC70, 0xBD70, 0xBE70, 0xBF70, 0xC050, 0xC150,
   1.476 +	0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950,
   1.477 +	0xCA70, 0xCB70, 0xCC70, 0xCD70, 0xCE70, 0xCF70, 0xD050, 0xD150,
   1.478 +	0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950,
   1.479 +	0xDA70, 0xDB70, 0xDC70, 0xDD70, 0xDE70, 0xDF70, 0xE050, 0xE150,
   1.480 +	0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950,
   1.481 +	0xEA70, 0xEB70, 0xEC70, 0xED70, 0xEE70, 0xEF70, 0xF050, 0xF150,
   1.482 +	0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950,
   1.483 +	0xFA70, 0xFB70, 0xFC70, 0xFD70, 0xFE70, 0xFF70, 0x00D0, 0x0150,
   1.484 +	0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950,
   1.485 +	0x0A70, 0x0B70, 0x0C70, 0x0D70, 0x0E70, 0x0F70, 0x1050, 0x1150,
   1.486 +	0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950,
   1.487 +	0x1A70, 0x1B70, 0x1C70, 0x1D70, 0x1E70, 0x1F70, 0x2050, 0x2150,
   1.488 +	0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950,
   1.489 +	0x2A70, 0x2B70, 0x2C70, 0x2D70, 0x2E70, 0x2F70, 0x3050, 0x3150,
   1.490 +	0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950,
   1.491 +	0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150,
   1.492 +	0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950,
   1.493 +	0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150,
   1.494 +	0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950,
   1.495 +	0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150,
   1.496 +	0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950,
   1.497 +	0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150,
   1.498 +	0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950,
   1.499 +	0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150,
   1.500 +	0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950,
   1.501 +	0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150,
   1.502 +	0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950,
   1.503 +};
   1.504 +
   1.505 +u8 ZeroTable[] =
   1.506 +{
   1.507 +	0x80, 0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.508 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.509 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.510 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.511 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.512 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.513 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.514 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.515 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.516 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.517 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.518 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.519 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.520 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.521 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,
   1.522 +	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0,	0,	  0
   1.523 +};
   1.524 +
   1.525 +#define GBSAVE_GAME_VERSION_1 1
   1.526 +#define GBSAVE_GAME_VERSION_2 2
   1.527 +#define GBSAVE_GAME_VERSION_3 3
   1.528 +#define GBSAVE_GAME_VERSION_4 4
   1.529 +#define GBSAVE_GAME_VERSION_5 5
   1.530 +#define GBSAVE_GAME_VERSION_6 6
   1.531 +#define GBSAVE_GAME_VERSION_7 7
   1.532 +#define GBSAVE_GAME_VERSION_8 8
   1.533 +#define GBSAVE_GAME_VERSION_9 9
   1.534 +#define GBSAVE_GAME_VERSION_10 10
   1.535 +#define GBSAVE_GAME_VERSION_11 11
   1.536 +#define GBSAVE_GAME_VERSION_12 12
   1.537 +#define GBSAVE_GAME_VERSION_13 13
   1.538 +#define GBSAVE_GAME_VERSION GBSAVE_GAME_VERSION_13
   1.539 +
   1.540 +int inline gbGetValue(int min, int max, int v)
   1.541 +{
   1.542 +	return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0)));
   1.543 +}
   1.544 +
   1.545 +void gbGenFilter()
   1.546 +{
   1.547 +	for (int r = 0; r < 32; r++)
   1.548 +	{
   1.549 +		for (int g = 0; g < 32; g++)
   1.550 +		{
   1.551 +			for (int b = 0; b < 32; b++)
   1.552 +			{
   1.553 +				int nr = gbGetValue(gbGetValue(4, 14, g),
   1.554 +				                    gbGetValue(24, 29, g), r) - 4;
   1.555 +				int ng = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r),
   1.556 +				                               14 + gbGetValue(0, 3, r), b),
   1.557 +				                    gbGetValue(24 + gbGetValue(0, 3, r),
   1.558 +				                               29 + gbGetValue(0, 1, r), b), g) - 4;
   1.559 +				int nb = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r),
   1.560 +				                               14 + gbGetValue(0, 3, r), g),
   1.561 +				                    gbGetValue(24 + gbGetValue(0, 3, r),
   1.562 +				                               29 + gbGetValue(0, 1, r), g), b) - 4;
   1.563 +				gbColorFilter[(b << 10) | (g << 5) | r] = (nb << 10) | (ng << 5) | nr;
   1.564 +			}
   1.565 +		}
   1.566 +	}
   1.567 +}
   1.568 +
   1.569 +void gbCopyMemory(u16 d, u16 s, int count)
   1.570 +{
   1.571 +	while (count)
   1.572 +	{
   1.573 +		gbWriteMemoryQuick(d, gbReadMemoryQuick(s));
   1.574 +		s++;
   1.575 +		d++;
   1.576 +		count--;
   1.577 +	}
   1.578 +}
   1.579 +
   1.580 +void gbDoHdma()
   1.581 +{
   1.582 +	gbCopyMemory(gbHdmaDestination, gbHdmaSource, 0x10);
   1.583 +
   1.584 +	gbHdmaDestination += 0x10;
   1.585 +	gbHdmaSource	  += 0x10;
   1.586 +
   1.587 +	register_HDMA2 = (register_HDMA2 + 0x10) & 0xFF;
   1.588 +	if (register_HDMA2 == 0x00)
   1.589 +		register_HDMA1++;
   1.590 +
   1.591 +	register_HDMA4 = (register_HDMA4 + 0x10) & 0xFF;
   1.592 +	if (register_HDMA4 == 0x00)
   1.593 +		register_HDMA3++;
   1.594 +
   1.595 +	if (gbHdmaDestination == 0x96b0)
   1.596 +		gbHdmaBytes = gbHdmaBytes;
   1.597 +	gbHdmaBytes -= 0x10;
   1.598 +	register_HDMA5--;
   1.599 +	if (register_HDMA5 == 0xff)
   1.600 +		gbHdmaOn = 0;
   1.601 +}
   1.602 +
   1.603 +// fix for Harley and Lego Racers
   1.604 +void gbCompareLYToLYC()
   1.605 +{
   1.606 +	if (register_LY == register_LYC)
   1.607 +	{
   1.608 +		// mark that we have a match
   1.609 +		register_STAT |= 4;
   1.610 +
   1.611 +		// check if we need an interrupt
   1.612 +		if ((register_STAT & 0x40) && (register_IE & 2))
   1.613 +			gbInterrupt |= 2;
   1.614 +	}
   1.615 +	else   // no match
   1.616 +		register_STAT &= 0xfb;
   1.617 +}
   1.618 +
   1.619 +// FIXME: horrible kludge to workaround the frame timing bug
   1.620 +static int32 s_gbJoymask[4] = { 0, 0, 0, 0 };
   1.621 +
   1.622 +void gbWriteMemoryWrapped(register u16 address, register u8 value)
   1.623 +{
   1.624 +	if (address < 0x8000)
   1.625 +	{
   1.626 +#ifndef FINAL_VERSION
   1.627 +		if (memorydebug && (address > 0x3fff || address < 0x2000))
   1.628 +		{
   1.629 +			log("Memory register write %04x=%02x PC=%04x\n",
   1.630 +			    address,
   1.631 +			    value,
   1.632 +			    PC.W);
   1.633 +		}
   1.634 +#endif
   1.635 +		if (mapper)
   1.636 +			(*mapper)(address, value);
   1.637 +		return;
   1.638 +	}
   1.639 +
   1.640 +	if (address < 0xa000)
   1.641 +	{
   1.642 +		gbWriteMemoryQuick(address, value);
   1.643 +		return;
   1.644 +	}
   1.645 +
   1.646 +	if (address < 0xc000)
   1.647 +	{
   1.648 +#ifndef FINAL_VERSION
   1.649 +		if (memorydebug)
   1.650 +		{
   1.651 +			log("Memory register write %04x=%02x PC=%04x\n",
   1.652 +			    address,
   1.653 +			    value,
   1.654 +			    PC.W);
   1.655 +		}
   1.656 +#endif
   1.657 +
   1.658 +		if (mapper)
   1.659 +			(*mapperRAM)(address, value);
   1.660 +		return;
   1.661 +	}
   1.662 +
   1.663 +	if (address < 0xfe00)
   1.664 +	{
   1.665 +		gbWriteMemoryQuick(address, value);
   1.666 +		return;
   1.667 +	}
   1.668 +
   1.669 +	if (address < 0xff00)
   1.670 +	{
   1.671 +		gbMemory[address] = value;
   1.672 +		return;
   1.673 +	}
   1.674 +
   1.675 +	switch (address & 0x00ff)
   1.676 +	{
   1.677 +	case 0x00:
   1.678 +	{
   1.679 +		gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) |
   1.680 +		                    (value & 0x30));
   1.681 +		if (gbSgbMode)
   1.682 +		{
   1.683 +			gbSgbDoBitTransfer(value);
   1.684 +		}
   1.685 +
   1.686 +		return;
   1.687 +	}
   1.688 +
   1.689 +	case 0x01:
   1.690 +	{
   1.691 +		gbMemory[0xff01] = value;
   1.692 +		return;
   1.693 +	}
   1.694 +
   1.695 +	// serial control
   1.696 +	case 0x02:
   1.697 +	{
   1.698 +		gbSerialOn		 = (value & 0x80);
   1.699 +		gbMemory[0xff02] = value;
   1.700 +		if (gbSerialOn)
   1.701 +		{
   1.702 +			gbSerialTicks = GBSERIAL_CLOCK_TICKS;
   1.703 +#ifdef LINK_EMULATION
   1.704 +			if (linkConnected)
   1.705 +			{
   1.706 +				if (value & 1)
   1.707 +				{
   1.708 +					linkSendByte(0x100 | gbMemory[0xFF01]);
   1.709 +					Sleep(5);
   1.710 +				}
   1.711 +			}
   1.712 +#endif
   1.713 +		}
   1.714 +
   1.715 +		gbSerialBits = 0;
   1.716 +		return;
   1.717 +	}
   1.718 +
   1.719 +	// DIV register resets on any write
   1.720 +	case 0x04:
   1.721 +	{
   1.722 +		register_DIV = 0;
   1.723 +		return;
   1.724 +	}
   1.725 +	case 0x05:
   1.726 +		register_TIMA = value;
   1.727 +		return;
   1.728 +
   1.729 +	case 0x06:
   1.730 +		register_TMA = value;
   1.731 +		return;
   1.732 +
   1.733 +	// TIMER control
   1.734 +	case 0x07:
   1.735 +	{
   1.736 +		register_TAC = value;
   1.737 +
   1.738 +		gbTimerOn	= (value & 4);
   1.739 +		gbTimerMode = value & 3;
   1.740 +		//    register_TIMA = register_TMA;
   1.741 +		switch (gbTimerMode)
   1.742 +		{
   1.743 +		case 0:
   1.744 +			gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS;
   1.745 +			break;
   1.746 +		case 1:
   1.747 +			gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_1_CLOCK_TICKS;
   1.748 +			break;
   1.749 +		case 2:
   1.750 +			gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_2_CLOCK_TICKS;
   1.751 +			break;
   1.752 +		case 3:
   1.753 +			gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_3_CLOCK_TICKS;
   1.754 +			break;
   1.755 +		}
   1.756 +		return;
   1.757 +	}
   1.758 +
   1.759 +	case 0x0f:
   1.760 +	{
   1.761 +		register_IF = value;
   1.762 +		gbInterrupt = value;
   1.763 +		return;
   1.764 +	}
   1.765 +
   1.766 +	case 0x10:
   1.767 +	case 0x11:
   1.768 +	case 0x12:
   1.769 +	case 0x13:
   1.770 +	case 0x14:
   1.771 +	case 0x15:
   1.772 +	case 0x16:
   1.773 +	case 0x17:
   1.774 +	case 0x18:
   1.775 +	case 0x19:
   1.776 +	case 0x1a:
   1.777 +	case 0x1b:
   1.778 +	case 0x1c:
   1.779 +	case 0x1d:
   1.780 +	case 0x1e:
   1.781 +	case 0x1f:
   1.782 +	case 0x20:
   1.783 +	case 0x21:
   1.784 +	case 0x22:
   1.785 +	case 0x23:
   1.786 +	case 0x24:
   1.787 +	case 0x25:
   1.788 +	case 0x26:
   1.789 +	{
   1.790 +		SOUND_EVENT(address, value);
   1.791 +		return;
   1.792 +	}
   1.793 +	case 0x40:
   1.794 +	{
   1.795 +		int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80);
   1.796 +
   1.797 +		if (lcdChange)
   1.798 +		{
   1.799 +			if (value & 0x80)
   1.800 +			{
   1.801 +				gbLcdTicks	   = GBLCD_MODE_1_CLOCK_TICKS;
   1.802 +				gbLcdMode	   = 0;
   1.803 +				register_STAT &= 0xfc;
   1.804 +				register_LY	   = 0x00;
   1.805 +				// FIXME: horrible workaround
   1.806 +				if (gbNullInputHackTempEnabled && !useOldFrameTiming)
   1.807 +					memcpy(gbJoymask, s_gbJoymask, sizeof(gbJoymask));
   1.808 +			}
   1.809 +			else
   1.810 +			{
   1.811 +				gbLcdTicks	   = 0;
   1.812 +				gbLcdMode	   = 0;
   1.813 +				register_STAT &= 0xfc;
   1.814 +				register_LY	   = 0x00;
   1.815 +				// FIXME: horrible workaround
   1.816 +				memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask));
   1.817 +				if (gbNullInputHackTempEnabled && !useOldFrameTiming)
   1.818 +					memset(gbJoymask, 0, sizeof(gbJoymask));
   1.819 +			}
   1.820 +			//      compareLYToLYC();
   1.821 +		}
   1.822 +		// don't draw the window if it was not enabled and not being drawn before
   1.823 +		if (!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 &&
   1.824 +		    register_LY > register_WY)
   1.825 +			gbWindowLine = 144;
   1.826 +
   1.827 +		register_LCDC = value;
   1.828 +
   1.829 +		return;
   1.830 +	}
   1.831 +
   1.832 +	// STAT
   1.833 +	case 0x41:
   1.834 +	{
   1.835 +		//register_STAT = (register_STAT & 0x87) |
   1.836 +		//      (value & 0x7c);
   1.837 +		register_STAT = (value & 0xf8) | (register_STAT & 0x07);     // fix ?
   1.838 +		// GB bug from Devrs FAQ
   1.839 +		if (!gbCgbMode && (register_LCDC & 0x80) && gbLcdMode < 2)
   1.840 +			gbInterrupt |= 2;
   1.841 +		return;
   1.842 +	}
   1.843 +
   1.844 +	// SCY
   1.845 +	case 0x42:
   1.846 +	{
   1.847 +		register_SCY = value;
   1.848 +		return;
   1.849 +	}
   1.850 +
   1.851 +	// SCX
   1.852 +	case 0x43:
   1.853 +	{
   1.854 +		register_SCX = value;
   1.855 +		return;
   1.856 +	}
   1.857 +
   1.858 +	// LY
   1.859 +	case 0x44:
   1.860 +	{
   1.861 +		// read only
   1.862 +		return;
   1.863 +	}
   1.864 +
   1.865 +	// LYC
   1.866 +	case 0x45:
   1.867 +	{
   1.868 +		register_LYC = value;
   1.869 +		if ((register_LCDC & 0x80))
   1.870 +		{
   1.871 +			gbCompareLYToLYC();
   1.872 +		}
   1.873 +		return;
   1.874 +	}
   1.875 +
   1.876 +	// DMA!
   1.877 +	case 0x46:
   1.878 +	{
   1.879 +		int source = value * 0x0100;
   1.880 +
   1.881 +		gbCopyMemory(0xfe00,
   1.882 +		             source,
   1.883 +		             0xa0);
   1.884 +		register_DMA = value;
   1.885 +		return;
   1.886 +	}
   1.887 +
   1.888 +	// BGP
   1.889 +	case 0x47:
   1.890 +	{
   1.891 +		gbBgp[0] = value & 0x03;
   1.892 +		gbBgp[1] = (value & 0x0c) >> 2;
   1.893 +		gbBgp[2] = (value & 0x30) >> 4;
   1.894 +		gbBgp[3] = (value & 0xc0) >> 6;
   1.895 +		break;
   1.896 +	}
   1.897 +
   1.898 +	// OBP0
   1.899 +	case 0x48:
   1.900 +	{
   1.901 +		gbObp0[0] = value & 0x03;
   1.902 +		gbObp0[1] = (value & 0x0c) >> 2;
   1.903 +		gbObp0[2] = (value & 0x30) >> 4;
   1.904 +		gbObp0[3] = (value & 0xc0) >> 6;
   1.905 +		break;
   1.906 +	}
   1.907 +
   1.908 +	// OBP1
   1.909 +	case 0x49:
   1.910 +	{
   1.911 +		gbObp1[0] = value & 0x03;
   1.912 +		gbObp1[1] = (value & 0x0c) >> 2;
   1.913 +		gbObp1[2] = (value & 0x30) >> 4;
   1.914 +		gbObp1[3] = (value & 0xc0) >> 6;
   1.915 +		break;
   1.916 +	}
   1.917 +
   1.918 +	case 0x4a:
   1.919 +		register_WY = value;
   1.920 +		return;
   1.921 +
   1.922 +	case 0x4b:
   1.923 +		register_WX = value;
   1.924 +		return;
   1.925 +
   1.926 +	// KEY1
   1.927 +	case 0x4d:
   1.928 +	{
   1.929 +		if (gbCgbMode)
   1.930 +		{
   1.931 +			gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1);
   1.932 +			return;
   1.933 +		}
   1.934 +		break;
   1.935 +	}
   1.936 +
   1.937 +	// VBK
   1.938 +	case 0x4f:
   1.939 +	{
   1.940 +		if (gbCgbMode)
   1.941 +		{
   1.942 +			value = value & 1;
   1.943 +			if (value == gbVramBank)
   1.944 +				return;
   1.945 +
   1.946 +			int vramAddress = value * 0x2000;
   1.947 +			gbMemoryMap[0x08] = &gbVram[vramAddress];
   1.948 +			gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000];
   1.949 +
   1.950 +			gbVramBank	 = value;
   1.951 +			register_VBK = value;
   1.952 +		}
   1.953 +		return;
   1.954 +		break;
   1.955 +	}
   1.956 +
   1.957 +	// HDMA1
   1.958 +	case 0x51:
   1.959 +	{
   1.960 +		if (gbCgbMode)
   1.961 +		{
   1.962 +			if (value > 0x7f && value < 0xa0)
   1.963 +				value = 0;
   1.964 +
   1.965 +			gbHdmaSource = (value << 8) | (register_HDMA2 & 0xf0);
   1.966 +
   1.967 +			register_HDMA1 = value;
   1.968 +			return;
   1.969 +		}
   1.970 +		break;
   1.971 +	}
   1.972 +
   1.973 +	// HDMA2
   1.974 +	case 0x52:
   1.975 +	{
   1.976 +		if (gbCgbMode)
   1.977 +		{
   1.978 +			value = value & 0xf0;
   1.979 +
   1.980 +			gbHdmaSource = (register_HDMA1 << 8) | (value);
   1.981 +
   1.982 +			register_HDMA2 = value;
   1.983 +			return;
   1.984 +		}
   1.985 +		break;
   1.986 +	}
   1.987 +
   1.988 +	// HDMA3
   1.989 +	case 0x53:
   1.990 +	{
   1.991 +		if (gbCgbMode)
   1.992 +		{
   1.993 +			value = value & 0x1f;
   1.994 +			gbHdmaDestination  = (value << 8) | (register_HDMA4 & 0xf0);
   1.995 +			gbHdmaDestination += 0x8000;
   1.996 +			register_HDMA3	   = value;
   1.997 +			return;
   1.998 +		}
   1.999 +		break;
  1.1000 +	}
  1.1001 +
  1.1002 +	// HDMA4
  1.1003 +	case 0x54:
  1.1004 +	{
  1.1005 +		if (gbCgbMode)
  1.1006 +		{
  1.1007 +			value = value & 0xf0;
  1.1008 +			gbHdmaDestination  = ((register_HDMA3 & 0x1f) << 8) | value;
  1.1009 +			gbHdmaDestination += 0x8000;
  1.1010 +			register_HDMA4	   = value;
  1.1011 +			return;
  1.1012 +		}
  1.1013 +		break;
  1.1014 +	}
  1.1015 +
  1.1016 +	// HDMA5
  1.1017 +	case 0x55:
  1.1018 +	{
  1.1019 +		if (gbCgbMode)
  1.1020 +		{
  1.1021 +			gbHdmaBytes = 16 + (value & 0x7f) * 16;
  1.1022 +			if (gbHdmaOn)
  1.1023 +			{
  1.1024 +				if (value & 0x80)
  1.1025 +				{
  1.1026 +					register_HDMA5 = (value & 0x7f);
  1.1027 +				}
  1.1028 +				else
  1.1029 +				{
  1.1030 +					register_HDMA5 = 0xff;
  1.1031 +					gbHdmaOn	   = 0;
  1.1032 +				}
  1.1033 +			}
  1.1034 +			else
  1.1035 +			{
  1.1036 +				if (value & 0x80)
  1.1037 +				{
  1.1038 +					gbHdmaOn	   = 1;
  1.1039 +					register_HDMA5 = value & 0x7f;
  1.1040 +					if (gbLcdMode == 0)
  1.1041 +						gbDoHdma();
  1.1042 +				}
  1.1043 +				else
  1.1044 +				{
  1.1045 +					// we need to take the time it takes to complete the transfer into
  1.1046 +					// account... according to GB DEV FAQs, the setup time is the same
  1.1047 +					// for single and double speed, but the actual transfer takes the
  1.1048 +					// same time // (is that a typo?)
  1.1049 +					switch (gbDMASpeedVersion)
  1.1050 +					{
  1.1051 +					case 1:     // I believe this is more correct
  1.1052 +						// the lower 7 bits of FF55 specify the Transfer Length (divided by 16, minus 1)
  1.1053 +						// and we make gbDmaTicks twice as many cycles at double speed to make the transfer take the same time
  1.1054 +						if (gbSpeed)
  1.1055 +							gbDmaTicks = 16 * ((value & 0x7f) + 1);
  1.1056 +						else
  1.1057 +							gbDmaTicks = 8 * ((value & 0x7f) + 1);
  1.1058 +						break;
  1.1059 +					case 0:     // here for backward compatibility
  1.1060 +						// I think this was a guess that approximates the above in most but not all games
  1.1061 +						if (gbSpeed)
  1.1062 +							gbDmaTicks = 231 + 16 * (value & 0x7f);
  1.1063 +						else
  1.1064 +							gbDmaTicks = 231 + 8 * (value & 0x7f);
  1.1065 +						break;
  1.1066 +					default:     // shouldn't happen
  1.1067 +						//assert(0);
  1.1068 +						break;
  1.1069 +					}
  1.1070 +					gbCopyMemory(gbHdmaDestination, gbHdmaSource, gbHdmaBytes);
  1.1071 +					gbHdmaDestination += gbHdmaBytes;
  1.1072 +					gbHdmaSource	  += gbHdmaBytes;
  1.1073 +
  1.1074 +					register_HDMA3 = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f;
  1.1075 +					register_HDMA4 = gbHdmaDestination & 0xf0;
  1.1076 +					register_HDMA1 = (gbHdmaSource >> 8) & 0xff;
  1.1077 +					register_HDMA2 = gbHdmaSource & 0xf0;
  1.1078 +				}
  1.1079 +			}
  1.1080 +			return;
  1.1081 +		}
  1.1082 +		break;
  1.1083 +	}
  1.1084 +
  1.1085 +	// BCPS
  1.1086 +	case 0x68:
  1.1087 +	{
  1.1088 +		if (gbCgbMode)
  1.1089 +		{
  1.1090 +			int paletteIndex = (value & 0x3f) >> 1;
  1.1091 +			int paletteHiLo	 = (value & 0x01);
  1.1092 +
  1.1093 +			gbMemory[0xff68] = value;
  1.1094 +			gbMemory[0xff69] = (paletteHiLo ?
  1.1095 +			                    (gbPalette[paletteIndex] >> 8) :
  1.1096 +			                    (gbPalette[paletteIndex] & 0x00ff));
  1.1097 +			return;
  1.1098 +		}
  1.1099 +		break;
  1.1100 +	}
  1.1101 +
  1.1102 +	// BCPD
  1.1103 +	case 0x69:
  1.1104 +	{
  1.1105 +		if (gbCgbMode)
  1.1106 +		{
  1.1107 +			int v = gbMemory[0xff68];
  1.1108 +			int paletteIndex = (v & 0x3f) >> 1;
  1.1109 +			int paletteHiLo	 = (v & 0x01);
  1.1110 +			gbMemory[0xff69]		= value;
  1.1111 +			gbPalette[paletteIndex] = (paletteHiLo ?
  1.1112 +			                           ((value << 8) | (gbPalette[paletteIndex] & 0xff)) :
  1.1113 +			                           ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff;
  1.1114 +
  1.1115 +			if (gbMemory[0xff68] & 0x80)
  1.1116 +			{
  1.1117 +				int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f;
  1.1118 +
  1.1119 +				gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index;
  1.1120 +
  1.1121 +				gbMemory[0xff69] = (index & 1 ?
  1.1122 +				                    (gbPalette[index >> 1] >> 8) :
  1.1123 +				                    (gbPalette[index >> 1] & 0x00ff));
  1.1124 +			}
  1.1125 +			return;
  1.1126 +		}
  1.1127 +		break;
  1.1128 +	}
  1.1129 +
  1.1130 +	// OCPS
  1.1131 +	case 0x6a:
  1.1132 +	{
  1.1133 +		if (gbCgbMode)
  1.1134 +		{
  1.1135 +			int paletteIndex = (value & 0x3f) >> 1;
  1.1136 +			int paletteHiLo	 = (value & 0x01);
  1.1137 +
  1.1138 +			paletteIndex += 32;
  1.1139 +
  1.1140 +			gbMemory[0xff6a] = value;
  1.1141 +			gbMemory[0xff6b] = (paletteHiLo ?
  1.1142 +			                    (gbPalette[paletteIndex] >> 8) :
  1.1143 +			                    (gbPalette[paletteIndex] & 0x00ff));
  1.1144 +			return;
  1.1145 +		}
  1.1146 +		break;
  1.1147 +	}
  1.1148 +
  1.1149 +	// OCPD
  1.1150 +	case 0x6b:
  1.1151 +	{
  1.1152 +		if (gbCgbMode)
  1.1153 +		{
  1.1154 +			int v = gbMemory[0xff6a];
  1.1155 +			int paletteIndex = (v & 0x3f) >> 1;
  1.1156 +			int paletteHiLo	 = (v & 0x01);
  1.1157 +
  1.1158 +			paletteIndex += 32;
  1.1159 +
  1.1160 +			gbMemory[0xff6b]		= value;
  1.1161 +			gbPalette[paletteIndex] = (paletteHiLo ?
  1.1162 +			                           ((value << 8) | (gbPalette[paletteIndex] & 0xff)) :
  1.1163 +			                           ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff;
  1.1164 +			if (gbMemory[0xff6a] & 0x80)
  1.1165 +			{
  1.1166 +				int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f;
  1.1167 +
  1.1168 +				gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index;
  1.1169 +
  1.1170 +				gbMemory[0xff6b] = (index & 1 ?
  1.1171 +				                    (gbPalette[(index >> 1) + 32] >> 8) :
  1.1172 +				                    (gbPalette[(index >> 1) + 32] & 0x00ff));
  1.1173 +			}
  1.1174 +			return;
  1.1175 +		}
  1.1176 +		break;
  1.1177 +	}
  1.1178 +
  1.1179 +	// SVBK
  1.1180 +	case 0x70:
  1.1181 +	{
  1.1182 +		if (gbCgbMode)
  1.1183 +		{
  1.1184 +			value = value & 7;
  1.1185 +
  1.1186 +			int bank = value;
  1.1187 +			if (value == 0)
  1.1188 +				bank = 1;
  1.1189 +
  1.1190 +			if (bank == gbWramBank)
  1.1191 +				return;
  1.1192 +
  1.1193 +			int wramAddress = bank * 0x1000;
  1.1194 +			gbMemoryMap[0x0d] = &gbWram[wramAddress];
  1.1195 +
  1.1196 +			gbWramBank	  = bank;
  1.1197 +			register_SVBK = value;
  1.1198 +			return;
  1.1199 +		}
  1.1200 +		break;
  1.1201 +	}
  1.1202 +
  1.1203 +	case 0xff:
  1.1204 +	{
  1.1205 +		register_IE	 = value;
  1.1206 +		register_IF &= value;
  1.1207 +		return;
  1.1208 +	}
  1.1209 +	}
  1.1210 +
  1.1211 +	gbWriteMemoryQuick(address, value);
  1.1212 +}
  1.1213 +
  1.1214 +u8 gbReadOpcode(register u16 address)
  1.1215 +{
  1.1216 +	if (gbCheatMap[address])
  1.1217 +		return gbCheatRead(address);
  1.1218 +
  1.1219 +	// the following fix does more than Echo RAM fix, anyway...
  1.1220 +	switch (gbEchoRAMFixOn ? (address >> 12) & 0x000f : address & 0xf000)
  1.1221 +	{
  1.1222 +	case 0x0a:
  1.1223 +	case 0x0b:
  1.1224 +		if (mapperReadRAM)
  1.1225 +			return mapperReadRAM(address);
  1.1226 +		break;
  1.1227 +	case 0x0f:
  1.1228 +		if (address > 0xff00)
  1.1229 +		{
  1.1230 +			switch (address & 0x00ff)
  1.1231 +			{
  1.1232 +			case 0x04:
  1.1233 +				return register_DIV;
  1.1234 +			case 0x05:
  1.1235 +				return register_TIMA;
  1.1236 +			case 0x06:
  1.1237 +				return register_TMA;
  1.1238 +			case 0x07:
  1.1239 +				return (0xf8 | register_TAC);
  1.1240 +			case 0x0f:
  1.1241 +				return (0xe0 | register_IF);
  1.1242 +			case 0x40:
  1.1243 +				return register_LCDC;
  1.1244 +			case 0x41:
  1.1245 +				return (0x80 | register_STAT);
  1.1246 +			case 0x42:
  1.1247 +				return register_SCY;
  1.1248 +			case 0x43:
  1.1249 +				return register_SCX;
  1.1250 +			case 0x44:
  1.1251 +				return register_LY;
  1.1252 +			case 0x45:
  1.1253 +				return register_LYC;
  1.1254 +			case 0x46:
  1.1255 +				return register_DMA;
  1.1256 +			case 0x4a:
  1.1257 +				return register_WY;
  1.1258 +			case 0x4b:
  1.1259 +				return register_WX;
  1.1260 +			case 0x4f:
  1.1261 +				return (0xfe | register_VBK);
  1.1262 +			case 0x51:
  1.1263 +				return register_HDMA1;
  1.1264 +			case 0x52:
  1.1265 +				return register_HDMA2;
  1.1266 +			case 0x53:
  1.1267 +				return register_HDMA3;
  1.1268 +			case 0x54:
  1.1269 +				return register_HDMA4;
  1.1270 +			case 0x55:
  1.1271 +				return register_HDMA5;
  1.1272 +			case 0x70:
  1.1273 +				return (0xf8 | register_SVBK);
  1.1274 +			case 0xff:
  1.1275 +				return register_IE;
  1.1276 +			}
  1.1277 +		}
  1.1278 +		break;
  1.1279 +	}
  1.1280 +	return gbReadMemoryQuick(address);
  1.1281 +}
  1.1282 +
  1.1283 +void gbWriteMemory(register u16 address, register u8 value)
  1.1284 +{
  1.1285 +	gbWriteMemoryWrapped(address, value);
  1.1286 +	CallRegisteredLuaMemHook(address, 1, value, LUAMEMHOOK_WRITE);
  1.1287 +}
  1.1288 +
  1.1289 +u8 gbReadMemory(register u16 address)
  1.1290 +{
  1.1291 +	if (gbCheatMap[address])
  1.1292 +		return gbCheatRead(address);
  1.1293 +
  1.1294 +	if (address < 0xa000)
  1.1295 +		return gbReadMemoryQuick(address);
  1.1296 +
  1.1297 +	if (address < 0xc000)
  1.1298 +	{
  1.1299 +#ifndef FINAL_VERSION
  1.1300 +		if (memorydebug)
  1.1301 +		{
  1.1302 +			log("Memory register read %04x PC=%04x\n",
  1.1303 +			    address,
  1.1304 +			    PC.W);
  1.1305 +		}
  1.1306 +#endif
  1.1307 +
  1.1308 +		if (mapperReadRAM)
  1.1309 +			return mapperReadRAM(address);
  1.1310 +		return gbReadMemoryQuick(address);
  1.1311 +	}
  1.1312 +
  1.1313 +	if (address >= 0xff00)
  1.1314 +	{
  1.1315 +		switch (address & 0x00ff)
  1.1316 +		{
  1.1317 +		case 0x00:
  1.1318 +		{
  1.1319 +			if (gbSgbMode)
  1.1320 +			{
  1.1321 +				gbSgbReadingController |= 4;
  1.1322 +				gbSgbResetPacketState();
  1.1323 +			}
  1.1324 +
  1.1325 +			int b = gbMemory[0xff00];
  1.1326 +
  1.1327 +			if ((b & 0x30) == 0x20)
  1.1328 +			{
  1.1329 +				b &= 0xf0;
  1.1330 +
  1.1331 +				int joy = 0;
  1.1332 +				if (gbSgbMode && gbSgbMultiplayer)
  1.1333 +				{
  1.1334 +					switch (gbSgbNextController)
  1.1335 +					{
  1.1336 +					case 0x0f:
  1.1337 +						joy = 0;
  1.1338 +						break;
  1.1339 +					case 0x0e:
  1.1340 +						joy = 1;
  1.1341 +						break;
  1.1342 +					case 0x0d:
  1.1343 +						joy = 2;
  1.1344 +						break;
  1.1345 +					case 0x0c:
  1.1346 +						joy = 3;
  1.1347 +						break;
  1.1348 +					default:
  1.1349 +						joy = 0;
  1.1350 +					}
  1.1351 +				}
  1.1352 +				int joystate = gbJoymask[joy];
  1.1353 +				if (!(joystate & 128))
  1.1354 +					b |= 0x08;
  1.1355 +				if (!(joystate & 64))
  1.1356 +					b |= 0x04;
  1.1357 +				if (!(joystate & 32))
  1.1358 +					b |= 0x02;
  1.1359 +				if (!(joystate & 16))
  1.1360 +					b |= 0x01;
  1.1361 +
  1.1362 +				gbMemory[0xff00] = b;
  1.1363 +			}
  1.1364 +			else if ((b & 0x30) == 0x10)
  1.1365 +			{
  1.1366 +				b &= 0xf0;
  1.1367 +
  1.1368 +				int joy = 0;
  1.1369 +				if (gbSgbMode && gbSgbMultiplayer)
  1.1370 +				{
  1.1371 +					switch (gbSgbNextController)
  1.1372 +					{
  1.1373 +					case 0x0f:
  1.1374 +						joy = 0;
  1.1375 +						break;
  1.1376 +					case 0x0e:
  1.1377 +						joy = 1;
  1.1378 +						break;
  1.1379 +					case 0x0d:
  1.1380 +						joy = 2;
  1.1381 +						break;
  1.1382 +					case 0x0c:
  1.1383 +						joy = 3;
  1.1384 +						break;
  1.1385 +					default:
  1.1386 +						joy = 0;
  1.1387 +					}
  1.1388 +				}
  1.1389 +				int joystate = gbJoymask[joy];
  1.1390 +				if (!(joystate & 8))
  1.1391 +					b |= 0x08;
  1.1392 +				if (!(joystate & 4))
  1.1393 +					b |= 0x04;
  1.1394 +				if (!(joystate & 2))
  1.1395 +					b |= 0x02;
  1.1396 +				if (!(joystate & 1))
  1.1397 +					b |= 0x01;
  1.1398 +
  1.1399 +				gbMemory[0xff00] = b;
  1.1400 +			}
  1.1401 +			else
  1.1402 +			{
  1.1403 +				if (gbSgbMode && gbSgbMultiplayer)
  1.1404 +				{
  1.1405 +					gbMemory[0xff00] = 0xf0 | gbSgbNextController;
  1.1406 +				}
  1.1407 +				else
  1.1408 +				{
  1.1409 +					gbMemory[0xff00] = 0xff;
  1.1410 +				}
  1.1411 +			}
  1.1412 +		}
  1.1413 +			GBSystemCounters.lagged = false;
  1.1414 +			return gbMemory[0xff00];
  1.1415 +			break;
  1.1416 +		case 0x01:
  1.1417 +			return gbMemory[0xff01];
  1.1418 +		case 0x04:
  1.1419 +			return register_DIV;
  1.1420 +		case 0x05:
  1.1421 +			return register_TIMA;
  1.1422 +		case 0x06:
  1.1423 +			return register_TMA;
  1.1424 +		case 0x07:
  1.1425 +			return (0xf8 | register_TAC);
  1.1426 +		case 0x0f:
  1.1427 +			return (0xe0 | register_IF);
  1.1428 +		case 0x40:
  1.1429 +			return register_LCDC;
  1.1430 +		case 0x41:
  1.1431 +			return (0x80 | register_STAT);
  1.1432 +		case 0x42:
  1.1433 +			return register_SCY;
  1.1434 +		case 0x43:
  1.1435 +			return register_SCX;
  1.1436 +		case 0x44:
  1.1437 +			return register_LY;
  1.1438 +		case 0x45:
  1.1439 +			return register_LYC;
  1.1440 +		case 0x46:
  1.1441 +			return register_DMA;
  1.1442 +		case 0x4a:
  1.1443 +			return register_WY;
  1.1444 +		case 0x4b:
  1.1445 +			return register_WX;
  1.1446 +		case 0x4f:
  1.1447 +			return (0xfe | register_VBK);
  1.1448 +		case 0x51:
  1.1449 +			return register_HDMA1;
  1.1450 +		case 0x52:
  1.1451 +			return register_HDMA2;
  1.1452 +		case 0x53:
  1.1453 +			return register_HDMA3;
  1.1454 +		case 0x54:
  1.1455 +			return register_HDMA4;
  1.1456 +		case 0x55:
  1.1457 +			return register_HDMA5;
  1.1458 +		case 0x70:
  1.1459 +			return (0xf8 | register_SVBK);
  1.1460 +		case 0xff:
  1.1461 +			return register_IE;
  1.1462 +		}
  1.1463 +	}
  1.1464 +
  1.1465 +	return gbReadMemoryQuick(address);
  1.1466 +}
  1.1467 +
  1.1468 +void gbVblank_interrupt()
  1.1469 +{
  1.1470 +	if (IFF & 0x80)
  1.1471 +	{
  1.1472 +		PC.W++;
  1.1473 +		IFF &= 0x7f;
  1.1474 +	}
  1.1475 +	gbInterrupt &= 0xfe;
  1.1476 +
  1.1477 +	IFF			&= 0x7e;
  1.1478 +	register_IF &= 0xfe;
  1.1479 +
  1.1480 +	gbWriteMemory(--SP.W, PC.B.B1);
  1.1481 +	gbWriteMemory(--SP.W, PC.B.B0);
  1.1482 +	PC.W = 0x40;
  1.1483 +}
  1.1484 +
  1.1485 +void gbLcd_interrupt()
  1.1486 +{
  1.1487 +	if (IFF & 0x80)
  1.1488 +	{
  1.1489 +		PC.W++;
  1.1490 +		IFF &= 0x7f;
  1.1491 +	}
  1.1492 +	gbInterrupt &= 0xfd;
  1.1493 +	IFF			&= 0x7e;
  1.1494 +	register_IF &= 0xfd;
  1.1495 +
  1.1496 +	gbWriteMemory(--SP.W, PC.B.B1);
  1.1497 +	gbWriteMemory(--SP.W, PC.B.B0);
  1.1498 +
  1.1499 +	PC.W = 0x48;
  1.1500 +}
  1.1501 +
  1.1502 +void gbTimer_interrupt()
  1.1503 +{
  1.1504 +	if (IFF & 0x80)
  1.1505 +	{
  1.1506 +		PC.W++;
  1.1507 +		IFF &= 0x7f;
  1.1508 +	}
  1.1509 +	IFF			&= 0x7e;
  1.1510 +	gbInterrupt &= 0xfb;
  1.1511 +	register_IF &= 0xfb;
  1.1512 +
  1.1513 +	gbWriteMemory(--SP.W, PC.B.B1);
  1.1514 +	gbWriteMemory(--SP.W, PC.B.B0);
  1.1515 +
  1.1516 +	PC.W = 0x50;
  1.1517 +}
  1.1518 +
  1.1519 +void gbSerial_interrupt()
  1.1520 +{
  1.1521 +	if (IFF & 0x80)
  1.1522 +	{
  1.1523 +		PC.W++;
  1.1524 +		IFF &= 0x7f;
  1.1525 +	}
  1.1526 +	IFF			&= 0x7e;
  1.1527 +	gbInterrupt &= 0xf7;
  1.1528 +	register_IF &= 0xf7;
  1.1529 +
  1.1530 +	gbWriteMemory(--SP.W, PC.B.B1);
  1.1531 +	gbWriteMemory(--SP.W, PC.B.B0);
  1.1532 +
  1.1533 +	PC.W = 0x58;
  1.1534 +}
  1.1535 +
  1.1536 +void gbJoypad_interrupt()
  1.1537 +{
  1.1538 +	if (IFF & 0x80)
  1.1539 +	{
  1.1540 +		PC.W++;
  1.1541 +		IFF &= 0x7f;
  1.1542 +	}
  1.1543 +	IFF			&= 0x7e;
  1.1544 +	gbInterrupt &= 0xef;
  1.1545 +	register_IF &= 0xef;
  1.1546 +
  1.1547 +	gbWriteMemory(--SP.W, PC.B.B1);
  1.1548 +	gbWriteMemory(--SP.W, PC.B.B0);
  1.1549 +
  1.1550 +	PC.W = 0x60;
  1.1551 +}
  1.1552 +
  1.1553 +void gbSpeedSwitch()
  1.1554 +{
  1.1555 +	if (gbSpeed == 0)
  1.1556 +	{
  1.1557 +		gbSpeed = 1;
  1.1558 +		GBLCD_MODE_0_CLOCK_TICKS   = 51 * 2; //127; //51 * 2;
  1.1559 +		GBLCD_MODE_1_CLOCK_TICKS   = 1140 * 2;
  1.1560 +		GBLCD_MODE_2_CLOCK_TICKS   = 20 * 2; //52; //20 * 2;
  1.1561 +		GBLCD_MODE_3_CLOCK_TICKS   = 43 * 2; //99; //43 * 2;
  1.1562 +		GBDIV_CLOCK_TICKS		   = 64 * 2;
  1.1563 +		GBLY_INCREMENT_CLOCK_TICKS = 114 * 2;
  1.1564 +		GBTIMER_MODE_0_CLOCK_TICKS = 256; //256*2;
  1.1565 +		GBTIMER_MODE_1_CLOCK_TICKS = 4; //4*2;
  1.1566 +		GBTIMER_MODE_2_CLOCK_TICKS = 16; //16*2;
  1.1567 +		GBTIMER_MODE_3_CLOCK_TICKS = 64; //64*2;
  1.1568 +		GBSERIAL_CLOCK_TICKS	   = 128 * 2;
  1.1569 +		gbDivTicks *= 2;
  1.1570 +		gbLcdTicks *= 2;
  1.1571 +		gbLcdLYIncrementTicks *= 2;
  1.1572 +		//    timerTicks *= 2;
  1.1573 +		//    timerClockTicks *= 2;
  1.1574 +		gbSerialTicks	 *= 2;
  1.1575 +		SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS * 2;
  1.1576 +		soundTicks		 *= 2;
  1.1577 +		//    synchronizeTicks *= 2;
  1.1578 +		//    SYNCHRONIZE_CLOCK_TICKS *= 2;
  1.1579 +	}
  1.1580 +	else
  1.1581 +	{
  1.1582 +		gbSpeed = 0;
  1.1583 +		GBLCD_MODE_0_CLOCK_TICKS   = 51;
  1.1584 +		GBLCD_MODE_1_CLOCK_TICKS   = 1140;
  1.1585 +		GBLCD_MODE_2_CLOCK_TICKS   = 20;
  1.1586 +		GBLCD_MODE_3_CLOCK_TICKS   = 43;
  1.1587 +		GBDIV_CLOCK_TICKS		   = 64;
  1.1588 +		GBLY_INCREMENT_CLOCK_TICKS = 114;
  1.1589 +		GBTIMER_MODE_0_CLOCK_TICKS = 256;
  1.1590 +		GBTIMER_MODE_1_CLOCK_TICKS = 4;
  1.1591 +		GBTIMER_MODE_2_CLOCK_TICKS = 16;
  1.1592 +		GBTIMER_MODE_3_CLOCK_TICKS = 64;
  1.1593 +		GBSERIAL_CLOCK_TICKS	   = 128;
  1.1594 +		gbDivTicks /= 2;
  1.1595 +		gbLcdTicks /= 2;
  1.1596 +		gbLcdLYIncrementTicks /= 2;
  1.1597 +		//    timerTicks /= 2;
  1.1598 +		//    timerClockTicks /= 2;
  1.1599 +		gbSerialTicks	 /= 2;
  1.1600 +		SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS;
  1.1601 +		soundTicks		 /= 2;
  1.1602 +		//    synchronizeTicks /= 2;
  1.1603 +		//    SYNCHRONIZE_CLOCK_TICKS /= 2;
  1.1604 +	}
  1.1605 +}
  1.1606 +
  1.1607 +void gbGetHardwareType()
  1.1608 +{
  1.1609 +	gbCgbMode = 0;
  1.1610 +	if (gbRom[0x143] & 0x80)
  1.1611 +	{
  1.1612 +		if (gbEmulatorType == 0 ||
  1.1613 +		    gbEmulatorType == 1 ||
  1.1614 +		    gbEmulatorType == 4 ||
  1.1615 +		    gbEmulatorType == 5 ||
  1.1616 +		    (gbRom[0x146] != 0x03 && (gbEmulatorType == 2)))
  1.1617 +		{
  1.1618 +			gbCgbMode = 1;
  1.1619 +		}
  1.1620 +	}
  1.1621 +
  1.1622 +	if (gbSgbMode == 2)
  1.1623 +	{
  1.1624 +		gbSgbMode = 0;
  1.1625 +		return;
  1.1626 +	}
  1.1627 +
  1.1628 +	gbSgbMode = 0;
  1.1629 +	if (gbRom[0x146] == 0x03)
  1.1630 +	{
  1.1631 +		if (gbEmulatorType == 0 ||
  1.1632 +		    gbEmulatorType == 2 ||
  1.1633 +		    gbEmulatorType == 5 ||
  1.1634 +		    (!(gbRom[0x143] & 0x80) && (gbEmulatorType == 1 || gbEmulatorType == 4)))
  1.1635 +			gbSgbMode = 1;
  1.1636 +	}
  1.1637 +}
  1.1638 +
  1.1639 +void gbReset(bool userReset)
  1.1640 +{
  1.1641 +	// movie must be closed while opening/creating a movie
  1.1642 +	if (userReset && VBAMovieRecording())
  1.1643 +	{
  1.1644 +		VBAMovieSignalReset();
  1.1645 +		return;
  1.1646 +	}
  1.1647 +
  1.1648 +	if (!VBAMovieActive())
  1.1649 +	{
  1.1650 +		GBSystemCounters.frameCount = 0;
  1.1651 +		GBSystemCounters.lagCount	= 0;
  1.1652 +		GBSystemCounters.extraCount = 0;
  1.1653 +		GBSystemCounters.lagged		= true;
  1.1654 +		GBSystemCounters.laggedLast = true;
  1.1655 +	}
  1.1656 +
  1.1657 +	SP.W = 0xfffe;
  1.1658 +	AF.W = 0x01b0;
  1.1659 +	BC.W = 0x0013;
  1.1660 +	DE.W = 0x00d8;
  1.1661 +	HL.W = 0x014d;
  1.1662 +	PC.W = 0x0100;
  1.1663 +	IFF	 = 0;
  1.1664 +	gbInterrupt		= 1;
  1.1665 +	gbInterruptWait = 0;
  1.1666 +
  1.1667 +	register_DIV   = 0;
  1.1668 +	register_TIMA  = 0;
  1.1669 +	register_TMA   = 0;
  1.1670 +	register_TAC   = 0;
  1.1671 +	register_IF	   = 1;
  1.1672 +	register_LCDC  = 0x91;
  1.1673 +	register_STAT  = 0;
  1.1674 +	register_SCY   = 0;
  1.1675 +	register_SCX   = 0;
  1.1676 +	register_LY	   = 0;
  1.1677 +	register_LYC   = 0;
  1.1678 +	register_DMA   = 0;
  1.1679 +	register_WY	   = 0;
  1.1680 +	register_WX	   = 0;
  1.1681 +	register_VBK   = 0;
  1.1682 +	register_HDMA1 = 0;
  1.1683 +	register_HDMA2 = 0;
  1.1684 +	register_HDMA3 = 0;
  1.1685 +	register_HDMA4 = 0;
  1.1686 +	register_HDMA5 = 0;
  1.1687 +	register_SVBK  = 0;
  1.1688 +	register_IE	   = 0;
  1.1689 +
  1.1690 +	gbGetHardwareType();
  1.1691 +	if (gbCgbMode)
  1.1692 +	{
  1.1693 +		if (!gbVram)
  1.1694 +			gbVram = (u8 *)malloc(0x4000 + 4);
  1.1695 +		if (!gbWram)
  1.1696 +			gbWram = (u8 *)malloc(0x8000 + 4);
  1.1697 +		memset(gbVram, 0, 0x4000 + 4);
  1.1698 +		memset(gbWram, 0, 0x8000 + 4);
  1.1699 +	}
  1.1700 +	else
  1.1701 +	{
  1.1702 +		if (gbVram)
  1.1703 +		{
  1.1704 +			free(gbVram);
  1.1705 +			gbVram = NULL;
  1.1706 +		}
  1.1707 +		if (gbWram)
  1.1708 +		{
  1.1709 +			free(gbWram);
  1.1710 +			gbWram = NULL;
  1.1711 +		}
  1.1712 +	}
  1.1713 +
  1.1714 +	// clean LineBuffer
  1.1715 +	if (gbLineBuffer)
  1.1716 +		memset(gbLineBuffer, 0, 160 * sizeof(u16));
  1.1717 +	// clean Pix
  1.1718 +	if (pix)
  1.1719 +		memset(pix, 0, 4 * 257 * 226);
  1.1720 +
  1.1721 +	if (gbCgbMode)
  1.1722 +	{
  1.1723 +		if (gbSgbMode)
  1.1724 +		{
  1.1725 +			if (gbEmulatorType == 5)
  1.1726 +				AF.W = 0xffb0;
  1.1727 +			else
  1.1728 +				AF.W = 0x01b0;
  1.1729 +			BC.W = 0x0013;
  1.1730 +			DE.W = 0x00d8;
  1.1731 +			HL.W = 0x014d;
  1.1732 +		}
  1.1733 +		else
  1.1734 +		{
  1.1735 +			AF.W = 0x11b0;
  1.1736 +			BC.W = 0x0000;
  1.1737 +			DE.W = 0xff56;
  1.1738 +			HL.W = 0x000d;
  1.1739 +		}
  1.1740 +		if (gbEmulatorType == 4)
  1.1741 +			BC.B.B1 |= 0x01;
  1.1742 +
  1.1743 +		register_HDMA5	 = 0xff;
  1.1744 +		gbMemory[0xff68] = 0xc0;
  1.1745 +		gbMemory[0xff6a] = 0xc0;
  1.1746 +
  1.1747 +		for (int i = 0; i < 64; i++)
  1.1748 +			gbPalette[i] = 0x7fff;
  1.1749 +	}
  1.1750 +	else
  1.1751 +	{
  1.1752 +		for (int i = 0; i < 8; i++)
  1.1753 +			gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i];
  1.1754 +	}
  1.1755 +
  1.1756 +	if (gbSpeed)
  1.1757 +	{
  1.1758 +		gbSpeedSwitch();
  1.1759 +		gbMemory[0xff4d] = 0;
  1.1760 +	}
  1.1761 +
  1.1762 +	gbDivTicks = GBDIV_CLOCK_TICKS;
  1.1763 +	gbLcdMode  = 2;
  1.1764 +	gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS;
  1.1765 +	gbLcdLYIncrementTicks = 0;
  1.1766 +	gbTimerTicks		  = 0;
  1.1767 +	gbTimerClockTicks	  = 0;
  1.1768 +	gbSerialTicks		  = 0;
  1.1769 +	gbSerialBits		  = 0;
  1.1770 +	gbSerialOn			  = 0;
  1.1771 +	gbWindowLine		  = -1;
  1.1772 +	gbTimerOn			  = 0;
  1.1773 +	gbTimerMode			  = 0;
  1.1774 +	//  gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS;
  1.1775 +	gbSpeed		 = 0;
  1.1776 +	gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0;
  1.1777 +
  1.1778 +	// FIXME: horrible kludge
  1.1779 +	memset(s_gbJoymask, 0, sizeof(s_gbJoymask));
  1.1780 +
  1.1781 +	if (gbCgbMode)
  1.1782 +	{
  1.1783 +		gbSpeed	 = 0;
  1.1784 +		gbHdmaOn = 0;
  1.1785 +		gbHdmaSource	  = 0x0000;
  1.1786 +		gbHdmaDestination = 0x8000;
  1.1787 +		gbVramBank		  = 0;
  1.1788 +		gbWramBank		  = 1;
  1.1789 +		register_LY		  = 0x90;
  1.1790 +		gbLcdMode		  = 1;
  1.1791 +	}
  1.1792 +
  1.1793 +	if (gbSgbMode)
  1.1794 +	{
  1.1795 +		gbSgbReset();
  1.1796 +	}
  1.1797 +
  1.1798 +	for (int i = 0; i < 4; i++)
  1.1799 +		gbBgp[i] = gbObp0[i] = gbObp1[i] = i;
  1.1800 +
  1.1801 +	memset(&gbDataMBC1, 0, sizeof(gbDataMBC1));
  1.1802 +	gbDataMBC1.mapperROMBank = 1;
  1.1803 +
  1.1804 +	gbDataMBC2.mapperRAMEnable = 0;
  1.1805 +	gbDataMBC2.mapperROMBank   = 1;
  1.1806 +
  1.1807 +	memset(&gbDataMBC3, 0, 6 * sizeof(int32));
  1.1808 +	gbDataMBC3.mapperROMBank = 1;
  1.1809 +
  1.1810 +	memset(&gbDataMBC5, 0, sizeof(gbDataMBC5));
  1.1811 +	gbDataMBC5.mapperROMBank = 1;
  1.1812 +	switch (gbRom[0x147])
  1.1813 +	{
  1.1814 +	case 0x1c:
  1.1815 +	case 0x1d:
  1.1816 +	case 0x1e:
  1.1817 +		gbDataMBC5.isRumbleCartridge = 1;
  1.1818 +	}
  1.1819 +
  1.1820 +	memset(&gbDataHuC1, 0, sizeof(gbDataHuC1));
  1.1821 +	gbDataHuC1.mapperROMBank = 1;
  1.1822 +
  1.1823 +	memset(&gbDataHuC3, 0, sizeof(gbDataHuC3));
  1.1824 +	gbDataHuC3.mapperROMBank = 1;
  1.1825 +
  1.1826 +	gbMemoryMap[0x00] = &gbRom[0x0000];
  1.1827 +	gbMemoryMap[0x01] = &gbRom[0x1000];
  1.1828 +	gbMemoryMap[0x02] = &gbRom[0x2000];
  1.1829 +	gbMemoryMap[0x03] = &gbRom[0x3000];
  1.1830 +	gbMemoryMap[0x04] = &gbRom[0x4000];
  1.1831 +	gbMemoryMap[0x05] = &gbRom[0x5000];
  1.1832 +	gbMemoryMap[0x06] = &gbRom[0x6000];
  1.1833 +	gbMemoryMap[0x07] = &gbRom[0x7000];
  1.1834 +	if (gbCgbMode)
  1.1835 +	{
  1.1836 +		gbMemoryMap[0x08] = &gbVram[0x0000];
  1.1837 +		gbMemoryMap[0x09] = &gbVram[0x1000];
  1.1838 +		gbMemoryMap[0x0a] = &gbMemory[0xa000];
  1.1839 +		gbMemoryMap[0x0b] = &gbMemory[0xb000];
  1.1840 +		gbMemoryMap[0x0c] = &gbMemory[0xc000];
  1.1841 +		gbMemoryMap[0x0d] = &gbWram[0x1000];
  1.1842 +		gbMemoryMap[0x0e] = &gbMemory[0xe000];
  1.1843 +		gbMemoryMap[0x0f] = &gbMemory[0xf000];
  1.1844 +	}
  1.1845 +	else
  1.1846 +	{
  1.1847 +		gbMemoryMap[0x08] = &gbMemory[0x8000];
  1.1848 +		gbMemoryMap[0x09] = &gbMemory[0x9000];
  1.1849 +		gbMemoryMap[0x0a] = &gbMemory[0xa000];
  1.1850 +		gbMemoryMap[0x0b] = &gbMemory[0xb000];
  1.1851 +		gbMemoryMap[0x0c] = &gbMemory[0xc000];
  1.1852 +		gbMemoryMap[0x0d] = &gbMemory[0xd000];
  1.1853 +		gbMemoryMap[0x0e] = &gbMemory[0xe000];
  1.1854 +		gbMemoryMap[0x0f] = &gbMemory[0xf000];
  1.1855 +	}
  1.1856 +
  1.1857 +	if (gbRam)
  1.1858 +	{
  1.1859 +		gbMemoryMap[0x0a] = &gbRam[0x0000];
  1.1860 +		gbMemoryMap[0x0b] = &gbRam[0x1000];
  1.1861 +	}
  1.1862 +
  1.1863 +	gbSoundReset();
  1.1864 +
  1.1865 +	systemResetSensor();
  1.1866 +
  1.1867 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  1.1868 +
  1.1869 +	gbLastTime	 = systemGetClock();
  1.1870 +	gbFrameCount = 0;
  1.1871 +
  1.1872 +	systemRefreshScreen();
  1.1873 +}
  1.1874 +
  1.1875 +void gbWriteSaveMBC1(const char *name)
  1.1876 +{
  1.1877 +	FILE *gzFile = fopen(name, "wb");
  1.1878 +
  1.1879 +	if (gzFile == NULL)
  1.1880 +	{
  1.1881 +		systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);
  1.1882 +		return;
  1.1883 +	}
  1.1884 +
  1.1885 +	fwrite(gbRam,
  1.1886 +	       1,
  1.1887 +	       gbRamSize,
  1.1888 +	       gzFile);
  1.1889 +
  1.1890 +	fclose(gzFile);
  1.1891 +}
  1.1892 +
  1.1893 +void gbWriteSaveMBC2(const char *name)
  1.1894 +{
  1.1895 +	FILE *file = fopen(name, "wb");
  1.1896 +
  1.1897 +	if (file == NULL)
  1.1898 +	{
  1.1899 +		systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);
  1.1900 +		return;
  1.1901 +	}
  1.1902 +
  1.1903 +	fwrite(&gbMemory[0xa000],
  1.1904 +	       1,
  1.1905 +	       256,
  1.1906 +	       file);
  1.1907 +
  1.1908 +	fclose(file);
  1.1909 +}
  1.1910 +
  1.1911 +void gbWriteSaveMBC3(const char *name, bool extendedSave)
  1.1912 +{
  1.1913 +	FILE *gzFile = fopen(name, "wb");
  1.1914 +
  1.1915 +	if (gzFile == NULL)
  1.1916 +	{
  1.1917 +		systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);
  1.1918 +		return;
  1.1919 +	}
  1.1920 +
  1.1921 +	fwrite(gbRam,
  1.1922 +	       1,
  1.1923 +	       gbRamSize,
  1.1924 +	       gzFile);
  1.1925 +
  1.1926 +	if (extendedSave)
  1.1927 +	{
  1.1928 +		//assert(sizeof(time_t) == 4);
  1.1929 +		fwrite(&gbDataMBC3.mapperSeconds,
  1.1930 +		       1,
  1.1931 +		       10 * sizeof(int32) + /*sizeof(time_t)*/4,
  1.1932 +		       gzFile);
  1.1933 +	}
  1.1934 +
  1.1935 +	fclose(gzFile);
  1.1936 +}
  1.1937 +
  1.1938 +void gbWriteSaveMBC5(const char *name)
  1.1939 +{
  1.1940 +	FILE *gzFile = fopen(name, "wb");
  1.1941 +
  1.1942 +	if (gzFile == NULL)
  1.1943 +	{
  1.1944 +		systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);
  1.1945 +		return;
  1.1946 +	}
  1.1947 +
  1.1948 +	fwrite(gbRam,
  1.1949 +	       1,
  1.1950 +	       gbRamSize,
  1.1951 +	       gzFile);
  1.1952 +
  1.1953 +	fclose(gzFile);
  1.1954 +}
  1.1955 +
  1.1956 +void gbWriteSaveMBC7(const char *name)
  1.1957 +{
  1.1958 +	FILE *file = fopen(name, "wb");
  1.1959 +
  1.1960 +	if (file == NULL)
  1.1961 +	{
  1.1962 +		systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);
  1.1963 +		return;
  1.1964 +	}
  1.1965 +
  1.1966 +	fwrite(&gbMemory[0xa000],
  1.1967 +	       1,
  1.1968 +	       256,
  1.1969 +	       file);
  1.1970 +
  1.1971 +	fclose(file);
  1.1972 +}
  1.1973 +
  1.1974 +bool gbReadSaveMBC1(const char *name)
  1.1975 +{
  1.1976 +	gzFile gzFile = gzopen(name, "rb");
  1.1977 +
  1.1978 +	if (gzFile == NULL)
  1.1979 +	{
  1.1980 +		return false;
  1.1981 +	}
  1.1982 +
  1.1983 +	int read = gzread(gzFile,
  1.1984 +	                  gbRam,
  1.1985 +	                  gbRamSize);
  1.1986 +
  1.1987 +	if (read != gbRamSize)
  1.1988 +	{
  1.1989 +		systemMessage(MSG_FAILED_TO_READ_SGM, N_("Failed to read complete save game %s (%d)"), name, read);
  1.1990 +		gzclose(gzFile);
  1.1991 +		return false;
  1.1992 +	}
  1.1993 +
  1.1994 +	gzclose(gzFile);
  1.1995 +	return true;
  1.1996 +}
  1.1997 +
  1.1998 +bool gbReadSaveMBC2(const char *name)
  1.1999 +{
  1.2000 +	FILE *file = fopen(name, "rb");
  1.2001 +
  1.2002 +	if (file == NULL)
  1.2003 +	{
  1.2004 +		return false;
  1.2005 +	}
  1.2006 +
  1.2007 +	int read = fread(&gbMemory[0xa000],
  1.2008 +	                 1,
  1.2009 +	                 256,
  1.2010 +	                 file);
  1.2011 +
  1.2012 +	if (read != 256)
  1.2013 +	{
  1.2014 +		systemMessage(MSG_FAILED_TO_READ_SGM,
  1.2015 +		              N_("Failed to read complete save game %s (%d)"), name, read);
  1.2016 +		fclose(file);
  1.2017 +		return false;
  1.2018 +	}
  1.2019 +
  1.2020 +	fclose(file);
  1.2021 +	return true;
  1.2022 +}
  1.2023 +
  1.2024 +bool gbReadSaveMBC3(const char *name)
  1.2025 +{
  1.2026 +	gzFile gzFile = gzopen(name, "rb");
  1.2027 +
  1.2028 +	if (gzFile == NULL)
  1.2029 +	{
  1.2030 +		return false;
  1.2031 +	}
  1.2032 +
  1.2033 +	int read = gzread(gzFile,
  1.2034 +	                  gbRam,
  1.2035 +	                  gbRamSize);
  1.2036 +
  1.2037 +	bool res = true;
  1.2038 +
  1.2039 +	if (read != gbRamSize)
  1.2040 +	{
  1.2041 +		systemMessage(MSG_FAILED_TO_READ_SGM,
  1.2042 +		              N_("Failed to read complete save game %s (%d)"), name, read);
  1.2043 +	}
  1.2044 +	else
  1.2045 +	{
  1.2046 +		//assert(sizeof(time_t) == 4);
  1.2047 +		read = gzread(gzFile,
  1.2048 +		              &gbDataMBC3.mapperSeconds,
  1.2049 +		              sizeof(int32) * 10 + /*sizeof(time_t)*/4);
  1.2050 +
  1.2051 +		if (read != (sizeof(int32) * 10 + /*sizeof(time_t)*/4) && read != 0)
  1.2052 +		{
  1.2053 +			systemMessage(MSG_FAILED_TO_READ_RTC,
  1.2054 +			              N_("Failed to read RTC from save game %s (continuing)"),
  1.2055 +			              name);
  1.2056 +			res = false;
  1.2057 +		}
  1.2058 +	}
  1.2059 +
  1.2060 +	gzclose(gzFile);
  1.2061 +	return res;
  1.2062 +}
  1.2063 +
  1.2064 +bool gbReadSaveMBC5(const char *name)
  1.2065 +{
  1.2066 +	gzFile gzFile = gzopen(name, "rb");
  1.2067 +
  1.2068 +	if (gzFile == NULL)
  1.2069 +	{
  1.2070 +		return false;
  1.2071 +	}
  1.2072 +
  1.2073 +	int read = gzread(gzFile,
  1.2074 +	                  gbRam,
  1.2075 +	                  gbRamSize);
  1.2076 +
  1.2077 +	if (read != gbRamSize)
  1.2078 +	{
  1.2079 +		systemMessage(MSG_FAILED_TO_READ_SGM,
  1.2080 +		              N_("Failed to read complete save game %s (%d)"), name, read);
  1.2081 +		gzclose(gzFile);
  1.2082 +		return false;
  1.2083 +	}
  1.2084 +
  1.2085 +	gzclose(gzFile);
  1.2086 +	return true;
  1.2087 +}
  1.2088 +
  1.2089 +bool gbReadSaveMBC7(const char *name)
  1.2090 +{
  1.2091 +	FILE *file = fopen(name, "rb");
  1.2092 +
  1.2093 +	if (file == NULL)
  1.2094 +	{
  1.2095 +		return false;
  1.2096 +	}
  1.2097 +
  1.2098 +	int read = fread(&gbMemory[0xa000],
  1.2099 +	                 1,
  1.2100 +	                 256,
  1.2101 +	                 file);
  1.2102 +
  1.2103 +	if (read != 256)
  1.2104 +	{
  1.2105 +		systemMessage(MSG_FAILED_TO_READ_SGM,
  1.2106 +		              N_("Failed to read complete save game %s (%d)"), name, read);
  1.2107 +		fclose(file);
  1.2108 +		return false;
  1.2109 +	}
  1.2110 +
  1.2111 +	fclose(file);
  1.2112 +	return true;
  1.2113 +}
  1.2114 +
  1.2115 +#if 0
  1.2116 +bool gbLoadBIOS(const char *biosFileName, bool useBiosFile)
  1.2117 +{
  1.2118 +	useBios = false;
  1.2119 +	if (useBiosFile)
  1.2120 +	{
  1.2121 +		useBios = utilLoadBIOS(bios, biosFileName, gbEmulatorType);
  1.2122 +		if (!useBios)
  1.2123 +		{
  1.2124 +			systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file"));
  1.2125 +		}
  1.2126 +	}
  1.2127 +	return useBios;
  1.2128 +}
  1.2129 +#endif
  1.2130 +
  1.2131 +void gbInit()
  1.2132 +{
  1.2133 +	gbGenFilter();
  1.2134 +	gbSgbInit();    // calls gbSgbReset()... whatever
  1.2135 +
  1.2136 +	gbMemory = (u8 *)malloc(65536 + 4);
  1.2137 +	memset(gbMemory, 0, 65536 + 4);
  1.2138 +	memset(gbPalette, 0, 2 * 128);
  1.2139 +
  1.2140 +	// HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel
  1.2141 +	origPix = (u8 *)calloc(1, 4 * 257 * 226 + 4);
  1.2142 +	pix		= origPix + 4;
  1.2143 +
  1.2144 +	gbLineBuffer = (u16 *)malloc(160 * sizeof(u16));
  1.2145 +}
  1.2146 +
  1.2147 +bool gbWriteBatteryFile(const char *file, bool extendedSave)
  1.2148 +{
  1.2149 +	if (gbBattery)
  1.2150 +	{
  1.2151 +		int type = gbRom[0x147];
  1.2152 +
  1.2153 +		switch (type)
  1.2154 +		{
  1.2155 +		case 0x03:
  1.2156 +			gbWriteSaveMBC1(file);
  1.2157 +			break;
  1.2158 +		case 0x06:
  1.2159 +			gbWriteSaveMBC2(file);
  1.2160 +			break;
  1.2161 +		case 0x0f:
  1.2162 +		case 0x10:
  1.2163 +		case 0x13:
  1.2164 +			gbWriteSaveMBC3(file, extendedSave);
  1.2165 +			break;
  1.2166 +		case 0x1b:
  1.2167 +		case 0x1e:
  1.2168 +			gbWriteSaveMBC5(file);
  1.2169 +			break;
  1.2170 +		case 0x22:
  1.2171 +			gbWriteSaveMBC7(file);
  1.2172 +			break;
  1.2173 +		case 0xff:
  1.2174 +			gbWriteSaveMBC1(file);
  1.2175 +			break;
  1.2176 +		}
  1.2177 +	}
  1.2178 +	return true;
  1.2179 +}
  1.2180 +
  1.2181 +bool gbWriteBatteryFile(const char *file)
  1.2182 +{
  1.2183 +	gbWriteBatteryFile(file, true);
  1.2184 +	return true;
  1.2185 +}
  1.2186 +
  1.2187 +bool gbWriteBatteryToStream(gzFile gzfile)
  1.2188 +{
  1.2189 +	// the GB save code is ugly, so rather than convert it all to use gzFiles, just save it to a temp file...
  1.2190 +#define TEMP_SAVE_FNAME ("tempvbawrite.sav")
  1.2191 +	bool retVal = gbWriteBatteryFile(TEMP_SAVE_FNAME, true);
  1.2192 +
  1.2193 +	// ...open the temp file and figure out its size...
  1.2194 +	FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "rb");
  1.2195 +	if (fileTemp == NULL)
  1.2196 +		return false;
  1.2197 +	fseek(fileTemp, 0, SEEK_END);
  1.2198 +	int len = (int) ftell(fileTemp);
  1.2199 +
  1.2200 +	// ...copy over the temp file...
  1.2201 +	char *temp = new char [len];
  1.2202 +	fseek(fileTemp, 0, SEEK_SET);
  1.2203 +	if (fread(temp, len, 1, fileTemp) != 1)
  1.2204 +	{
  1.2205 +		delete [] temp;
  1.2206 +		fclose(fileTemp);
  1.2207 +		return false;
  1.2208 +	}
  1.2209 +	fclose(fileTemp);
  1.2210 +	utilGzWrite(gzfile, temp, len);
  1.2211 +	delete [] temp;
  1.2212 +
  1.2213 +	// ... and delete the temp file
  1.2214 +	remove(TEMP_SAVE_FNAME);
  1.2215 +#undef TEMP_SAVE_FNAME
  1.2216 +
  1.2217 +	return retVal;
  1.2218 +}
  1.2219 +
  1.2220 +bool gbReadBatteryFile(const char *file)
  1.2221 +{
  1.2222 +	bool res = false;
  1.2223 +	if (gbBattery)
  1.2224 +	{
  1.2225 +		int type = gbRom[0x147];
  1.2226 +
  1.2227 +		switch (type)
  1.2228 +		{
  1.2229 +		case 0x03:
  1.2230 +			res = gbReadSaveMBC1(file);
  1.2231 +			break;
  1.2232 +		case 0x06:
  1.2233 +			res = gbReadSaveMBC2(file);
  1.2234 +			break;
  1.2235 +		case 0x0f:
  1.2236 +		case 0x10:
  1.2237 +		case 0x13:
  1.2238 +			if (!gbReadSaveMBC3(file))
  1.2239 +			{
  1.2240 +				struct tm *lt;
  1.2241 +				time_t tmp; //Small kludge to get it working on some systems where time_t has size 8.
  1.2242 +
  1.2243 +				if (VBAMovieActive() || VBAMovieLoading())
  1.2244 +				{
  1.2245 +					gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter() / 60;
  1.2246 +					lt = gmtime(&tmp);
  1.2247 +					gbDataMBC3.mapperLastTime=(u32)tmp;
  1.2248 +				}
  1.2249 +				else
  1.2250 +				{
  1.2251 +					time(&tmp);
  1.2252 +					gbDataMBC3.mapperLastTime=(u32)tmp;
  1.2253 +					lt = localtime(&tmp);
  1.2254 +				}
  1.2255 +				systemScreenMessage(ctime(&tmp), 4);
  1.2256 +				gbDataMBC3.mapperLastTime=(u32)tmp;
  1.2257 +
  1.2258 +				gbDataMBC3.mapperSeconds = lt->tm_sec;
  1.2259 +				gbDataMBC3.mapperMinutes = lt->tm_min;
  1.2260 +				gbDataMBC3.mapperHours	 = lt->tm_hour;
  1.2261 +				gbDataMBC3.mapperDays	 = lt->tm_yday & 255;
  1.2262 +				gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) |
  1.2263 +				                           (lt->tm_yday > 255 ? 1 : 0);
  1.2264 +				res = false;
  1.2265 +				break;
  1.2266 +			}
  1.2267 +			time_t tmp;
  1.2268 +			systemScreenMessage(ctime(&tmp), 4);
  1.2269 +			gbDataMBC3.mapperLastTime=(u32)tmp;
  1.2270 +			res = true;
  1.2271 +			break;
  1.2272 +		case 0x1b:
  1.2273 +		case 0x1e:
  1.2274 +			res = gbReadSaveMBC5(file);
  1.2275 +			break;
  1.2276 +		case 0x22:
  1.2277 +			res = gbReadSaveMBC7(file);
  1.2278 +		case 0xff:
  1.2279 +			res = gbReadSaveMBC1(file);
  1.2280 +			break;
  1.2281 +		}
  1.2282 +	}
  1.2283 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  1.2284 +	return res;
  1.2285 +}
  1.2286 +
  1.2287 +bool gbReadBatteryFromStream(gzFile gzfile)
  1.2288 +{
  1.2289 +	// the GB save code is ugly, so rather than convert it all to use gzFiles, just copy it to temp RAM...
  1.2290 +#define TEMP_SAVE_FNAME ("tempvbaread.sav")
  1.2291 +	int	  pos	 = gztell(gzfile);
  1.2292 +	int	  buflen = 1024;
  1.2293 +	// ...make a temp file and write it there...
  1.2294 +	FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "wb");
  1.2295 +	if (fileTemp == NULL)
  1.2296 +		return false;
  1.2297 +	int gzDeflated;
  1.2298 +	char *temp	 = new char [buflen];
  1.2299 +	while ((gzDeflated = utilGzRead(gzfile, temp, buflen)) != 0)
  1.2300 +	{
  1.2301 +		if (gzDeflated == -1 || fwrite(temp, gzDeflated, 1, fileTemp) != 1)
  1.2302 +		{
  1.2303 +			delete [] temp;
  1.2304 +			fclose(fileTemp);
  1.2305 +			gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that
  1.2306 +			                               // calls this right now does a seek afterwards so it doesn't matter for now, but it's
  1.2307 +			                               // still bad)
  1.2308 +			return false;
  1.2309 +		}
  1.2310 +	}
  1.2311 +	gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that calls this
  1.2312 +	                               // right now does a seek afterwards so it doesn't matter for now, but it's still bad)
  1.2313 +	fclose(fileTemp);
  1.2314 +	delete [] temp;
  1.2315 +
  1.2316 +	// ... load from the temp file...
  1.2317 +	bool retVal = gbReadBatteryFile(TEMP_SAVE_FNAME);
  1.2318 +
  1.2319 +	// ... and delete the temp file
  1.2320 +	remove(TEMP_SAVE_FNAME);
  1.2321 +#undef TEMP_SAVE_FNAME
  1.2322 +
  1.2323 +	return retVal;
  1.2324 +}
  1.2325 +
  1.2326 +bool gbReadGSASnapshot(const char *fileName)
  1.2327 +{
  1.2328 +	FILE *file = fopen(fileName, "rb");
  1.2329 +
  1.2330 +	if (!file)
  1.2331 +	{
  1.2332 +		systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
  1.2333 +		return false;
  1.2334 +	}
  1.2335 +
  1.2336 +	//  long size = ftell(file);
  1.2337 +	fseek(file, 0x4, SEEK_SET);
  1.2338 +	char buffer[16];
  1.2339 +	char buffer2[16];
  1.2340 +	fread(buffer, 1, 15, file);
  1.2341 +	buffer[15] = 0;
  1.2342 +	memcpy(buffer2, &gbRom[0x134], 15);
  1.2343 +	buffer2[15] = 0;
  1.2344 +	if (memcmp(buffer, buffer2, 15))
  1.2345 +	{
  1.2346 +		systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR,
  1.2347 +		              N_("Cannot import snapshot for %s. Current game is %s"),
  1.2348 +		              buffer,
  1.2349 +		              buffer2);
  1.2350 +		fclose(file);
  1.2351 +		return false;
  1.2352 +	}
  1.2353 +	fseek(file, 0x13, SEEK_SET);
  1.2354 +	int read   = 0;
  1.2355 +	int toRead = 0;
  1.2356 +	switch (gbRom[0x147])
  1.2357 +	{
  1.2358 +	case 0x03:
  1.2359 +	case 0x0f:
  1.2360 +	case 0x10:
  1.2361 +	case 0x13:
  1.2362 +	case 0x1b:
  1.2363 +	case 0x1e:
  1.2364 +	case 0xff:
  1.2365 +		read   = fread(gbRam, 1, gbRamSize, file);
  1.2366 +		toRead = gbRamSize;
  1.2367 +		break;
  1.2368 +	case 0x06:
  1.2369 +	case 0x22:
  1.2370 +		read   = fread(&gbMemory[0xa000], 1, 256, file);
  1.2371 +		toRead = 256;
  1.2372 +		break;
  1.2373 +	default:
  1.2374 +		systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE,
  1.2375 +		              N_("Unsupported snapshot file %s"),
  1.2376 +		              fileName);
  1.2377 +		fclose(file);
  1.2378 +		return false;
  1.2379 +	}
  1.2380 +	fclose(file);
  1.2381 +	gbReset();
  1.2382 +	return true;
  1.2383 +}
  1.2384 +
  1.2385 +variable_desc gbSaveGameStruct[] =
  1.2386 +{
  1.2387 +	{ &PC.W,					   sizeof(u16)						 },
  1.2388 +	{ &SP.W,					   sizeof(u16)						 },
  1.2389 +	{ &AF.W,					   sizeof(u16)						 },
  1.2390 +	{ &BC.W,					   sizeof(u16)						 },
  1.2391 +	{ &DE.W,					   sizeof(u16)						 },
  1.2392 +	{ &HL.W,					   sizeof(u16)						 },
  1.2393 +	{ &IFF,						   sizeof(u8)						 },
  1.2394 +	{ &GBLCD_MODE_0_CLOCK_TICKS,   sizeof(int32)					 },
  1.2395 +	{ &GBLCD_MODE_1_CLOCK_TICKS,   sizeof(int32)					 },
  1.2396 +	{ &GBLCD_MODE_2_CLOCK_TICKS,   sizeof(int32)					 },
  1.2397 +	{ &GBLCD_MODE_3_CLOCK_TICKS,   sizeof(int32)					 },
  1.2398 +	{ &GBDIV_CLOCK_TICKS,		   sizeof(int32)					 },
  1.2399 +	{ &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int32)					 },
  1.2400 +	{ &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int32)					 },
  1.2401 +	{ &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int32)					 },
  1.2402 +	{ &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int32)					 },
  1.2403 +	{ &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int32)					 },
  1.2404 +	{ &GBSERIAL_CLOCK_TICKS,	   sizeof(int32)					 },
  1.2405 +	{ &GBSYNCHRONIZE_CLOCK_TICKS,  sizeof(int32)					 },
  1.2406 +	{ &gbDivTicks,				   sizeof(int32)					 },
  1.2407 +	{ &gbLcdMode,				   sizeof(int32)					 },
  1.2408 +	{ &gbLcdTicks,				   sizeof(int32)					 },
  1.2409 +	{ &gbLcdLYIncrementTicks,	   sizeof(int32)					 },
  1.2410 +	{ &gbTimerTicks,			   sizeof(int32)					 },
  1.2411 +	{ &gbTimerClockTicks,		   sizeof(int32)					 },
  1.2412 +	{ &gbSerialTicks,			   sizeof(int32)					 },
  1.2413 +	{ &gbSerialBits,			   sizeof(int32)					 },
  1.2414 +	{ &gbInterrupt,				   sizeof(int32)					 },
  1.2415 +	{ &gbInterruptWait,			   sizeof(int32)					 },
  1.2416 +	{ &gbSynchronizeTicks,		   sizeof(int32)					 },
  1.2417 +	{ &gbTimerOn,				   sizeof(int32)					 },
  1.2418 +	{ &gbTimerMode,				   sizeof(int32)					 },
  1.2419 +	{ &gbSerialOn,				   sizeof(int32)					 },
  1.2420 +	{ &gbWindowLine,			   sizeof(int32)					 },
  1.2421 +	{ &gbCgbMode,				   sizeof(int32)					 },
  1.2422 +	{ &gbVramBank,				   sizeof(int32)					 },
  1.2423 +	{ &gbWramBank,				   sizeof(int32)					 },
  1.2424 +	{ &gbHdmaSource,			   sizeof(int32)					 },
  1.2425 +	{ &gbHdmaDestination,		   sizeof(int32)					 },
  1.2426 +	{ &gbHdmaBytes,				   sizeof(int32)					 },
  1.2427 +	{ &gbHdmaOn,				   sizeof(int32)					 },
  1.2428 +	{ &gbSpeed,					   sizeof(int32)					 },
  1.2429 +	{ &gbSgbMode,				   sizeof(int32)					 },
  1.2430 +	{ &register_DIV,			   sizeof(u8)						 },
  1.2431 +	{ &register_TIMA,			   sizeof(u8)						 },
  1.2432 +	{ &register_TMA,			   sizeof(u8)						 },
  1.2433 +	{ &register_TAC,			   sizeof(u8)						 },
  1.2434 +	{ &register_IF,				   sizeof(u8)						 },
  1.2435 +	{ &register_LCDC,			   sizeof(u8)						 },
  1.2436 +	{ &register_STAT,			   sizeof(u8)						 },
  1.2437 +	{ &register_SCY,			   sizeof(u8)						 },
  1.2438 +	{ &register_SCX,			   sizeof(u8)						 },
  1.2439 +	{ &register_LY,				   sizeof(u8)						 },
  1.2440 +	{ &register_LYC,			   sizeof(u8)						 },
  1.2441 +	{ &register_DMA,			   sizeof(u8)						 },
  1.2442 +	{ &register_WY,				   sizeof(u8)						 },
  1.2443 +	{ &register_WX,				   sizeof(u8)						 },
  1.2444 +	{ &register_VBK,			   sizeof(u8)						 },
  1.2445 +	{ &register_HDMA1,			   sizeof(u8)						 },
  1.2446 +	{ &register_HDMA2,			   sizeof(u8)						 },
  1.2447 +	{ &register_HDMA3,			   sizeof(u8)						 },
  1.2448 +	{ &register_HDMA4,			   sizeof(u8)						 },
  1.2449 +	{ &register_HDMA5,			   sizeof(u8)						 },
  1.2450 +	{ &register_SVBK,			   sizeof(u8)						 },
  1.2451 +	{ &register_IE,				   sizeof(u8)						 },
  1.2452 +	{ &gbBgp[0],				   sizeof(u8)						 },
  1.2453 +	{ &gbBgp[1],				   sizeof(u8)						 },
  1.2454 +	{ &gbBgp[2],				   sizeof(u8)						 },
  1.2455 +	{ &gbBgp[3],				   sizeof(u8)						 },
  1.2456 +	{ &gbObp0[0],				   sizeof(u8)						 },
  1.2457 +	{ &gbObp0[1],				   sizeof(u8)						 },
  1.2458 +	{ &gbObp0[2],				   sizeof(u8)						 },
  1.2459 +	{ &gbObp0[3],				   sizeof(u8)						 },
  1.2460 +	{ &gbObp1[0],				   sizeof(u8)						 },
  1.2461 +	{ &gbObp1[1],				   sizeof(u8)						 },
  1.2462 +	{ &gbObp1[2],				   sizeof(u8)						 },
  1.2463 +	{ &gbObp1[3],				   sizeof(u8)						 },
  1.2464 +	{ NULL,						   0								 }
  1.2465 +};
  1.2466 +
  1.2467 +bool gbWriteSaveStateToStream(gzFile gzFile)
  1.2468 +{
  1.2469 +	utilWriteInt(gzFile, GBSAVE_GAME_VERSION);
  1.2470 +
  1.2471 +	utilGzWrite(gzFile, &gbRom[0x134], 15);
  1.2472 +
  1.2473 +	utilWriteData(gzFile, gbSaveGameStruct);
  1.2474 +
  1.2475 +	utilGzWrite(gzFile, &IFF, 2);
  1.2476 +
  1.2477 +	if (gbSgbMode)
  1.2478 +	{
  1.2479 +		gbSgbSaveGame(gzFile);
  1.2480 +	}
  1.2481 +
  1.2482 +	utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1));
  1.2483 +	utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2));
  1.2484 +	//assert(sizeof(time_t) == 4);
  1.2485 +	utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3));
  1.2486 +	utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5));
  1.2487 +	utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1));
  1.2488 +	utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3));
  1.2489 +
  1.2490 +	// yes, this definitely needs to be saved, or loading paused games will show a black screen
  1.2491 +	// this is also necessary to be consistent with what the GBA saving does
  1.2492 +	utilGzWrite(gzFile, pix, 4 * 257 * 226);
  1.2493 +
  1.2494 +	utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16));
  1.2495 +	// todo: remove
  1.2496 +	utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16));
  1.2497 +
  1.2498 +	utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000);
  1.2499 +
  1.2500 +	if (gbRamSize && gbRam)
  1.2501 +	{
  1.2502 +		utilGzWrite(gzFile, gbRam, gbRamSize);
  1.2503 +	}
  1.2504 +
  1.2505 +	if (gbCgbMode)
  1.2506 +	{
  1.2507 +		utilGzWrite(gzFile, gbVram, 0x4000);
  1.2508 +		utilGzWrite(gzFile, gbWram, 0x8000);
  1.2509 +	}
  1.2510 +
  1.2511 +	gbSoundSaveGame(gzFile);
  1.2512 +
  1.2513 +	gbCheatsSaveGame(gzFile);
  1.2514 +
  1.2515 +	// new to re-recording version:
  1.2516 +	{
  1.2517 +		extern int32 sensorX, sensorY;
  1.2518 +		utilGzWrite(gzFile, &sensorX, sizeof(sensorX));
  1.2519 +		utilGzWrite(gzFile, &sensorY, sizeof(sensorY));
  1.2520 +		utilGzWrite(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get
  1.2521 +		                                                        // carried
  1.2522 +		                                                        // back on loading a snapshot!
  1.2523 +
  1.2524 +		bool8 movieActive = VBAMovieActive();
  1.2525 +		utilGzWrite(gzFile, &movieActive, sizeof(movieActive));
  1.2526 +		if (movieActive)
  1.2527 +		{
  1.2528 +			uint8 *movie_freeze_buf	 = NULL;
  1.2529 +			uint32 movie_freeze_size = 0;
  1.2530 +
  1.2531 +			VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size);
  1.2532 +			if (movie_freeze_buf)
  1.2533 +			{
  1.2534 +				utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size));
  1.2535 +				utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size);
  1.2536 +				delete [] movie_freeze_buf;
  1.2537 +			}
  1.2538 +			else
  1.2539 +			{
  1.2540 +				systemMessage(0, N_("Failed to save movie snapshot."));
  1.2541 +				return false;
  1.2542 +			}
  1.2543 +		}
  1.2544 +		utilGzWrite(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount));
  1.2545 +	}
  1.2546 +
  1.2547 +	// new to rerecording 19.4 wip (svn r22+):
  1.2548 +	{
  1.2549 +		utilGzWrite(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount));
  1.2550 +		utilGzWrite(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged));
  1.2551 +		utilGzWrite(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast));
  1.2552 +	}
  1.2553 +
  1.2554 +	return true;
  1.2555 +}
  1.2556 +
  1.2557 +bool gbWriteMemSaveState(char *memory, int available)
  1.2558 +{
  1.2559 +	gzFile gzFile = utilMemGzOpen(memory, available, "w");
  1.2560 +
  1.2561 +	if (gzFile == NULL)
  1.2562 +	{
  1.2563 +		return false;
  1.2564 +	}
  1.2565 +
  1.2566 +	bool res = gbWriteSaveStateToStream(gzFile);
  1.2567 +
  1.2568 +	long pos = utilGzTell(gzFile) + 8;
  1.2569 +
  1.2570 +	if (pos >= (available))
  1.2571 +		res = false;
  1.2572 +
  1.2573 +	utilGzClose(gzFile);
  1.2574 +
  1.2575 +	return res;
  1.2576 +}
  1.2577 +
  1.2578 +bool gbWriteSaveState(const char *name)
  1.2579 +{
  1.2580 +	gzFile gzFile = utilGzOpen(name, "wb");
  1.2581 +
  1.2582 +	if (gzFile == NULL)
  1.2583 +		return false;
  1.2584 +
  1.2585 +	bool res = gbWriteSaveStateToStream(gzFile);
  1.2586 +
  1.2587 +	utilGzClose(gzFile);
  1.2588 +	return res;
  1.2589 +}
  1.2590 +
  1.2591 +static int	tempStateID	  = 0;
  1.2592 +static int	tempFailCount = 0;
  1.2593 +static bool backupSafe	  = true;
  1.2594 +
  1.2595 +bool gbReadSaveStateFromStream(gzFile gzFile)
  1.2596 +{
  1.2597 +	int	 type;
  1.2598 +	char tempBackupName [128];
  1.2599 +	if (backupSafe)
  1.2600 +	{
  1.2601 +		sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++);
  1.2602 +		gbWriteSaveState(tempBackupName);
  1.2603 +	}
  1.2604 +
  1.2605 +	int version = utilReadInt(gzFile);
  1.2606 +
  1.2607 +	if (version > GBSAVE_GAME_VERSION || version < 0)
  1.2608 +	{
  1.2609 +		systemMessage(MSG_UNSUPPORTED_VB_SGM,
  1.2610 +		              N_("Unsupported VisualBoy save game version %d"), version);
  1.2611 +		goto failedLoadGB;
  1.2612 +	}
  1.2613 +
  1.2614 +	u8 romname[20];
  1.2615 +
  1.2616 +	utilGzRead(gzFile, romname, 15);
  1.2617 +
  1.2618 +	if (memcmp(&gbRom[0x134], romname, 15) != 0)
  1.2619 +	{
  1.2620 +		systemMessage(MSG_CANNOT_LOAD_SGM_FOR,
  1.2621 +		              N_("Cannot load save game for %s. Playing %s"),
  1.2622 +		              romname, &gbRom[0x134]);
  1.2623 +		goto failedLoadGB;
  1.2624 +	}
  1.2625 +
  1.2626 +	utilReadData(gzFile, gbSaveGameStruct);
  1.2627 +
  1.2628 +	if (version >= GBSAVE_GAME_VERSION_7)
  1.2629 +	{
  1.2630 +		utilGzRead(gzFile, &IFF, 2);
  1.2631 +	}
  1.2632 +
  1.2633 +	if (gbSgbMode)
  1.2634 +	{
  1.2635 +		gbSgbReadGame(gzFile, version);
  1.2636 +	}
  1.2637 +	else
  1.2638 +	{
  1.2639 +		gbSgbMask = 0; // loading a game at the wrong time causes no display
  1.2640 +	}
  1.2641 +
  1.2642 +	utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1));
  1.2643 +	utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2));
  1.2644 +	if (version < GBSAVE_GAME_VERSION_4)
  1.2645 +		// prior to version 4, there was no adjustment for the time the game
  1.2646 +		// was last played, so we have less to read. This needs update if the
  1.2647 +		// structure changes again.
  1.2648 +		utilGzRead(gzFile, &gbDataMBC3, sizeof(int32) * 10);
  1.2649 +	else
  1.2650 +	{
  1.2651 +		//assert(sizeof(time_t) == 4);
  1.2652 +		utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3));
  1.2653 +	}
  1.2654 +	utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5));
  1.2655 +	utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1));
  1.2656 +	utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3));
  1.2657 +
  1.2658 +	if (version >= GBSAVE_GAME_VERSION_12)
  1.2659 +	{
  1.2660 +		utilGzRead(gzFile, pix, 4 * 257 * 226);
  1.2661 +	}
  1.2662 +	else
  1.2663 +	{
  1.2664 +		memset(pix, 0, 257 * 226 * sizeof(u32));
  1.2665 +//		if(version < GBSAVE_GAME_VERSION_5)
  1.2666 +//			utilGzRead(gzFile, pix, 256*224*sizeof(u16));
  1.2667 +	}
  1.2668 +
  1.2669 +	if (version < GBSAVE_GAME_VERSION_6)
  1.2670 +	{
  1.2671 +		utilGzRead(gzFile, gbPalette, 64 * sizeof(u16));
  1.2672 +	}
  1.2673 +	else
  1.2674 +		utilGzRead(gzFile, gbPalette, 128 * sizeof(u16));
  1.2675 +
  1.2676 +	// todo: remove
  1.2677 +	utilGzRead(gzFile, gbPalette, 128 * sizeof(u16));
  1.2678 +
  1.2679 +	if (version < GBSAVE_GAME_VERSION_10)
  1.2680 +	{
  1.2681 +		if (!gbCgbMode && !gbSgbMode)
  1.2682 +		{
  1.2683 +			for (int i = 0; i < 8; i++)
  1.2684 +				gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i];
  1.2685 +		}
  1.2686 +	}
  1.2687 +
  1.2688 +	utilGzRead(gzFile, &gbMemory[0x8000], 0x8000);
  1.2689 +
  1.2690 +	if (gbRamSize && gbRam)
  1.2691 +	{
  1.2692 +		utilGzRead(gzFile, gbRam, gbRamSize);
  1.2693 +	}
  1.2694 +
  1.2695 +	gbMemoryMap[0x00] = &gbRom[0x0000];
  1.2696 +	gbMemoryMap[0x01] = &gbRom[0x1000];
  1.2697 +	gbMemoryMap[0x02] = &gbRom[0x2000];
  1.2698 +	gbMemoryMap[0x03] = &gbRom[0x3000];
  1.2699 +	gbMemoryMap[0x04] = &gbRom[0x4000];
  1.2700 +	gbMemoryMap[0x05] = &gbRom[0x5000];
  1.2701 +	gbMemoryMap[0x06] = &gbRom[0x6000];
  1.2702 +	gbMemoryMap[0x07] = &gbRom[0x7000];
  1.2703 +	gbMemoryMap[0x08] = &gbMemory[0x8000];
  1.2704 +	gbMemoryMap[0x09] = &gbMemory[0x9000];
  1.2705 +	gbMemoryMap[0x0a] = &gbMemory[0xa000];
  1.2706 +	gbMemoryMap[0x0b] = &gbMemory[0xb000];
  1.2707 +	gbMemoryMap[0x0c] = &gbMemory[0xc000];
  1.2708 +	gbMemoryMap[0x0d] = &gbMemory[0xd000];
  1.2709 +	gbMemoryMap[0x0e] = &gbMemory[0xe000];
  1.2710 +	gbMemoryMap[0x0f] = &gbMemory[0xf000];
  1.2711 +
  1.2712 +	type = gbRom[0x147];
  1.2713 +
  1.2714 +	switch (type)
  1.2715 +	{
  1.2716 +	case 0x00:
  1.2717 +	case 0x01:
  1.2718 +	case 0x02:
  1.2719 +	case 0x03:
  1.2720 +		// MBC 1
  1.2721 +		memoryUpdateMapMBC1();
  1.2722 +		break;
  1.2723 +	case 0x05:
  1.2724 +	case 0x06:
  1.2725 +		// MBC2
  1.2726 +		memoryUpdateMapMBC2();
  1.2727 +		break;
  1.2728 +	case 0x0f:
  1.2729 +	case 0x10:
  1.2730 +	case 0x11:
  1.2731 +	case 0x12:
  1.2732 +	case 0x13:
  1.2733 +		// MBC 3
  1.2734 +		memoryUpdateMapMBC3();
  1.2735 +		break;
  1.2736 +	case 0x19:
  1.2737 +	case 0x1a:
  1.2738 +	case 0x1b:
  1.2739 +		// MBC5
  1.2740 +		memoryUpdateMapMBC5();
  1.2741 +		break;
  1.2742 +	case 0x1c:
  1.2743 +	case 0x1d:
  1.2744 +	case 0x1e:
  1.2745 +		// MBC 5 Rumble
  1.2746 +		memoryUpdateMapMBC5();
  1.2747 +		break;
  1.2748 +	case 0x22:
  1.2749 +		// MBC 7
  1.2750 +		memoryUpdateMapMBC7();
  1.2751 +		break;
  1.2752 +	case 0xfe:
  1.2753 +		// HuC3
  1.2754 +		memoryUpdateMapHuC3();
  1.2755 +		break;
  1.2756 +	case 0xff:
  1.2757 +		// HuC1
  1.2758 +		memoryUpdateMapHuC1();
  1.2759 +		break;
  1.2760 +	}
  1.2761 +
  1.2762 +	if (gbCgbMode)
  1.2763 +	{
  1.2764 +		if (!gbVram)
  1.2765 +			gbVram = (u8 *)malloc(0x4000 + 4);
  1.2766 +		if (!gbWram)
  1.2767 +			gbWram = (u8 *)malloc(0x8000 + 4);
  1.2768 +		utilGzRead(gzFile, gbVram, 0x4000);
  1.2769 +		utilGzRead(gzFile, gbWram, 0x8000);
  1.2770 +
  1.2771 +		int value = register_SVBK;
  1.2772 +		if (value == 0)
  1.2773 +			value = 1;
  1.2774 +
  1.2775 +		gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000];
  1.2776 +		gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000];
  1.2777 +		gbMemoryMap[0x0d] = &gbWram[value * 0x1000];
  1.2778 +	}
  1.2779 +	else
  1.2780 +	{
  1.2781 +		if (gbVram)
  1.2782 +		{
  1.2783 +			free(gbVram);
  1.2784 +			gbVram = NULL;
  1.2785 +		}
  1.2786 +		if (gbWram)
  1.2787 +		{
  1.2788 +			free(gbWram);
  1.2789 +			gbWram = NULL;
  1.2790 +		}
  1.2791 +	}
  1.2792 +
  1.2793 +	gbSoundReadGame(version, gzFile);
  1.2794 +
  1.2795 +#if 0
  1.2796 +	if (gbBorderOn)
  1.2797 +	{
  1.2798 +		gbSgbRenderBorder();
  1.2799 +	}
  1.2800 +
  1.2801 +	systemRefreshScreen();
  1.2802 +#endif
  1.2803 +
  1.2804 +	if (version > GBSAVE_GAME_VERSION_1)
  1.2805 +		gbCheatsReadGame(gzFile, version);
  1.2806 +
  1.2807 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  1.2808 +
  1.2809 +	if (version >= GBSAVE_GAME_VERSION_11) // new to re-recording version:
  1.2810 +	{
  1.2811 +		extern int32 sensorX, sensorY; // from SDL.cpp
  1.2812 +		utilGzRead(gzFile, &sensorX, sizeof(sensorX));
  1.2813 +		utilGzRead(gzFile, &sensorY, sizeof(sensorY));
  1.2814 +		utilGzRead(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get carried
  1.2815 +		                                                       // back on loading a snapshot!
  1.2816 +
  1.2817 +		bool8 movieSnapshot;
  1.2818 +		utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot));
  1.2819 +		if (VBAMovieActive() && !movieSnapshot)
  1.2820 +		{
  1.2821 +			systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active."));
  1.2822 +			goto failedLoadGB;
  1.2823 +		}
  1.2824 +
  1.2825 +		if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added
  1.2826 +		                   // later on in the save format
  1.2827 +		{
  1.2828 +			uint32 movieInputDataSize = 0;
  1.2829 +			utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize));
  1.2830 +			uint8 *local_movie_data = new uint8 [movieInputDataSize];
  1.2831 +			int	   readBytes		= utilGzRead(gzFile, local_movie_data, movieInputDataSize);
  1.2832 +			if (readBytes != movieInputDataSize)
  1.2833 +			{
  1.2834 +				systemMessage(0, N_("Corrupt movie snapshot."));
  1.2835 +				if (local_movie_data)
  1.2836 +					delete [] local_movie_data;
  1.2837 +				goto failedLoadGB;
  1.2838 +			}
  1.2839 +			int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize);
  1.2840 +			if (local_movie_data)
  1.2841 +				delete [] local_movie_data;
  1.2842 +			if (code != MOVIE_SUCCESS && VBAMovieActive())
  1.2843 +			{
  1.2844 +				char errStr [1024];
  1.2845 +				strcpy(errStr, "Failed to load movie snapshot");
  1.2846 +				switch (code)
  1.2847 +				{
  1.2848 +				case MOVIE_NOT_FROM_THIS_MOVIE:
  1.2849 +					strcat(errStr, ";\nSnapshot not from this movie"); break;
  1.2850 +				case MOVIE_NOT_FROM_A_MOVIE:
  1.2851 +					strcat(errStr, ";\nNot a movie snapshot"); break;                    // shouldn't get here...
  1.2852 +				case MOVIE_SNAPSHOT_INCONSISTENT:
  1.2853 +					strcat(errStr, ";\nSnapshot inconsistent with movie"); break;
  1.2854 +				case MOVIE_WRONG_FORMAT:
  1.2855 +					strcat(errStr, ";\nWrong format"); break;
  1.2856 +				}
  1.2857 +				strcat(errStr, ".");
  1.2858 +				systemMessage(0, N_(errStr));
  1.2859 +				goto failedLoadGB;
  1.2860 +			}
  1.2861 +		}
  1.2862 +		utilGzRead(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount));
  1.2863 +	}
  1.2864 +
  1.2865 +	if (version >= GBSAVE_GAME_VERSION_13)   // new to rerecording 19.4 wip (svn r22+):
  1.2866 +	{
  1.2867 +		utilGzRead(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount));
  1.2868 +		utilGzRead(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged));
  1.2869 +		utilGzRead(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast));
  1.2870 +	}
  1.2871 +
  1.2872 +	if (backupSafe)
  1.2873 +	{
  1.2874 +		remove(tempBackupName);
  1.2875 +		tempFailCount = 0;
  1.2876 +	}
  1.2877 +
  1.2878 +	for (int i = 0; i < 4; ++i)
  1.2879 +		systemSetJoypad(i, gbJoymask[i] & 0xFFFF);
  1.2880 +
  1.2881 +	// FIXME: horrible kludge
  1.2882 +	memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask));
  1.2883 +
  1.2884 +	VBAUpdateButtonPressDisplay();
  1.2885 +	VBAUpdateFrameCountDisplay();
  1.2886 +	systemRefreshScreen();
  1.2887 +	return true;
  1.2888 +
  1.2889 +failedLoadGB:
  1.2890 +	if (backupSafe)
  1.2891 +	{
  1.2892 +		tempFailCount++;
  1.2893 +		if (tempFailCount < 3) // fail no more than 2 times in a row
  1.2894 +			gbReadSaveState(tempBackupName);
  1.2895 +		remove(tempBackupName);
  1.2896 +	}
  1.2897 +	return false;
  1.2898 +}
  1.2899 +
  1.2900 +bool gbReadMemSaveState(char *memory, int available)
  1.2901 +{
  1.2902 +	gzFile gzFile = utilMemGzOpen(memory, available, "r");
  1.2903 +
  1.2904 +	backupSafe = false;
  1.2905 +	bool res = gbReadSaveStateFromStream(gzFile);
  1.2906 +	backupSafe = true;
  1.2907 +
  1.2908 +	utilGzClose(gzFile);
  1.2909 +
  1.2910 +	return res;
  1.2911 +}
  1.2912 +
  1.2913 +bool gbReadSaveState(const char *name)
  1.2914 +{
  1.2915 +	gzFile gzFile = utilGzOpen(name, "rb");
  1.2916 +
  1.2917 +	if (gzFile == NULL)
  1.2918 +	{
  1.2919 +		return false;
  1.2920 +	}
  1.2921 +
  1.2922 +	bool res = gbReadSaveStateFromStream(gzFile);
  1.2923 +
  1.2924 +	utilGzClose(gzFile);
  1.2925 +
  1.2926 +	return res;
  1.2927 +}
  1.2928 +
  1.2929 +bool gbWritePNGFile(const char *fileName)
  1.2930 +{
  1.2931 +	if (gbBorderOn)
  1.2932 +		return utilWritePNGFile(fileName, 256, 224, pix);
  1.2933 +	return utilWritePNGFile(fileName, 160, 144, pix);
  1.2934 +}
  1.2935 +
  1.2936 +bool gbWriteBMPFile(const char *fileName)
  1.2937 +{
  1.2938 +	if (gbBorderOn)
  1.2939 +		return utilWriteBMPFile(fileName, 256, 224, pix);
  1.2940 +	return utilWriteBMPFile(fileName, 160, 144, pix);
  1.2941 +}
  1.2942 +
  1.2943 +void gbCleanUp()
  1.2944 +{
  1.2945 +	newFrame	  = true;
  1.2946 +
  1.2947 +	GBSystemCounters.frameCount = 0;
  1.2948 +	GBSystemCounters.lagCount	= 0;
  1.2949 +	GBSystemCounters.extraCount = 0;
  1.2950 +	GBSystemCounters.lagged		= true;
  1.2951 +	GBSystemCounters.laggedLast = true;
  1.2952 +
  1.2953 +	if (gbRam != NULL)
  1.2954 +	{
  1.2955 +		free(gbRam);
  1.2956 +		gbRam = NULL;
  1.2957 +	}
  1.2958 +
  1.2959 +	if (gbRom != NULL)
  1.2960 +	{
  1.2961 +		free(gbRom);
  1.2962 +		gbRom = NULL;
  1.2963 +	}
  1.2964 +
  1.2965 +	if (gbMemory != NULL)
  1.2966 +	{
  1.2967 +		free(gbMemory);
  1.2968 +		gbMemory = NULL;
  1.2969 +	}
  1.2970 +
  1.2971 +	if (gbLineBuffer != NULL)
  1.2972 +	{
  1.2973 +		free(gbLineBuffer);
  1.2974 +		gbLineBuffer = NULL;
  1.2975 +	}
  1.2976 +
  1.2977 +	if (origPix != NULL)
  1.2978 +	{
  1.2979 +		free(origPix);
  1.2980 +		origPix = NULL;
  1.2981 +	}
  1.2982 +	pix = NULL;
  1.2983 +
  1.2984 +	gbSgbShutdown();
  1.2985 +
  1.2986 +	if (gbVram != NULL)
  1.2987 +	{
  1.2988 +		free(gbVram);
  1.2989 +		gbVram = NULL;
  1.2990 +	}
  1.2991 +
  1.2992 +	if (gbWram != NULL)
  1.2993 +	{
  1.2994 +		free(gbWram);
  1.2995 +		gbWram = NULL;
  1.2996 +	}
  1.2997 +
  1.2998 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  1.2999 +
  1.3000 +	memset(gbJoymask, 0, sizeof(gbJoymask));
  1.3001 +	// FIXME: horrible kludge
  1.3002 +	memset(s_gbJoymask, 0, sizeof(s_gbJoymask));
  1.3003 +
  1.3004 +	systemClearJoypads();
  1.3005 +	systemResetSensor();
  1.3006 +
  1.3007 +//	gbLastTime = gbFrameCount = 0;
  1.3008 +	systemRefreshScreen();
  1.3009 +}
  1.3010 +
  1.3011 +bool gbLoadRom(const char *szFile)
  1.3012 +{
  1.3013 +	int size = 0;
  1.3014 +
  1.3015 +	if (gbRom != NULL)
  1.3016 +	{
  1.3017 +		gbCleanUp();
  1.3018 +	}
  1.3019 +
  1.3020 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  1.3021 +
  1.3022 +	gbRom = utilLoad(szFile,
  1.3023 +	                 utilIsGBImage,
  1.3024 +	                 NULL,
  1.3025 +	                 size);
  1.3026 +	if (!gbRom)
  1.3027 +		return false;
  1.3028 +
  1.3029 +	gbRomSize = size;
  1.3030 +
  1.3031 +	return gbUpdateSizes();
  1.3032 +}
  1.3033 +
  1.3034 +bool gbUpdateSizes()
  1.3035 +{
  1.3036 +	if (gbRom[0x148] > 8)
  1.3037 +	{
  1.3038 +		systemMessage(MSG_UNSUPPORTED_ROM_SIZE,
  1.3039 +		              N_("Unsupported rom size %02x"), gbRom[0x148]);
  1.3040 +		return false;
  1.3041 +	}
  1.3042 +
  1.3043 +	if (gbRomSize < gbRomSizes[gbRom[0x148]])
  1.3044 +	{
  1.3045 +		gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]);
  1.3046 +	}
  1.3047 +	gbRomSize	  = gbRomSizes[gbRom[0x148]];
  1.3048 +	gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]];
  1.3049 +
  1.3050 +	if (gbRom[0x149] > 5)
  1.3051 +	{
  1.3052 +		systemMessage(MSG_UNSUPPORTED_RAM_SIZE,
  1.3053 +		              N_("Unsupported ram size %02x"), gbRom[0x149]);
  1.3054 +		return false;
  1.3055 +	}
  1.3056 +
  1.3057 +	gbRamSize	  = gbRamSizes[gbRom[0x149]];
  1.3058 +	gbRamSizeMask = gbRamSizesMasks[gbRom[0x149]];
  1.3059 +
  1.3060 +	if (gbRamSize)
  1.3061 +	{
  1.3062 +		gbRam = (u8 *)malloc(gbRamSize + 4);
  1.3063 +		memset(gbRam, 0xFF, gbRamSize + 4);
  1.3064 +	}
  1.3065 +
  1.3066 +	int type = gbRom[0x147];
  1.3067 +
  1.3068 +	mapperReadRAM = NULL;
  1.3069 +
  1.3070 +	switch (type)
  1.3071 +	{
  1.3072 +	case 0x00:
  1.3073 +	case 0x01:
  1.3074 +	case 0x02:
  1.3075 +	case 0x03:
  1.3076 +		// MBC 1
  1.3077 +		mapper	  = mapperMBC1ROM;
  1.3078 +		mapperRAM = mapperMBC1RAM;
  1.3079 +		break;
  1.3080 +	case 0x05:
  1.3081 +	case 0x06:
  1.3082 +		// MBC2
  1.3083 +		mapper		  = mapperMBC2ROM;
  1.3084 +		mapperRAM	  = mapperMBC2RAM;
  1.3085 +		gbRamSize	  = 0x200;
  1.3086 +		gbRamSizeMask = 0x1ff;
  1.3087 +		break;
  1.3088 +	case 0x0f:
  1.3089 +	case 0x10:
  1.3090 +	case 0x11:
  1.3091 +	case 0x12:
  1.3092 +	case 0x13:
  1.3093 +		// MBC 3
  1.3094 +		mapper		  = mapperMBC3ROM;
  1.3095 +		mapperRAM	  = mapperMBC3RAM;
  1.3096 +		mapperReadRAM = mapperMBC3ReadRAM;
  1.3097 +		break;
  1.3098 +	case 0x19:
  1.3099 +	case 0x1a:
  1.3100 +	case 0x1b:
  1.3101 +		// MBC5
  1.3102 +		mapper	  = mapperMBC5ROM;
  1.3103 +		mapperRAM = mapperMBC5RAM;
  1.3104 +		break;
  1.3105 +	case 0x1c:
  1.3106 +	case 0x1d:
  1.3107 +	case 0x1e:
  1.3108 +		// MBC 5 Rumble
  1.3109 +		mapper	  = mapperMBC5ROM;
  1.3110 +		mapperRAM = mapperMBC5RAM;
  1.3111 +		break;
  1.3112 +	case 0x22:
  1.3113 +		// MBC 7
  1.3114 +		mapper		  = mapperMBC7ROM;
  1.3115 +		mapperRAM	  = mapperMBC7RAM;
  1.3116 +		mapperReadRAM = mapperMBC7ReadRAM;
  1.3117 +		break;
  1.3118 +	case 0xfe:
  1.3119 +		// HuC3
  1.3120 +		mapper		  = mapperHuC3ROM;
  1.3121 +		mapperRAM	  = mapperHuC3RAM;
  1.3122 +		mapperReadRAM = mapperHuC3ReadRAM;
  1.3123 +		break;
  1.3124 +	case 0xff:
  1.3125 +		// HuC1
  1.3126 +		mapper	  = mapperHuC1ROM;
  1.3127 +		mapperRAM = mapperHuC1RAM;
  1.3128 +		break;
  1.3129 +	default:
  1.3130 +		systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE,
  1.3131 +		              N_("Unknown cartridge type %02x"), type);
  1.3132 +		return false;
  1.3133 +	}
  1.3134 +
  1.3135 +	switch (type)
  1.3136 +	{
  1.3137 +	case 0x03:
  1.3138 +	case 0x06:
  1.3139 +	case 0x0f:
  1.3140 +	case 0x10:
  1.3141 +	case 0x13:
  1.3142 +	case 0x1b:
  1.3143 +	case 0x1d:
  1.3144 +	case 0x1e:
  1.3145 +	case 0x22:
  1.3146 +	case 0xff:
  1.3147 +		gbBattery = 1;
  1.3148 +		break;
  1.3149 +	}
  1.3150 +
  1.3151 +	gbInit();
  1.3152 +	gbReset();
  1.3153 +
  1.3154 +	return true;
  1.3155 +}
  1.3156 +
  1.3157 +void gbEmulate(int ticksToStop)
  1.3158 +{
  1.3159 +	gbRegister tempRegister;
  1.3160 +	u8		   tempValue;
  1.3161 +	s8		   offset;
  1.3162 +
  1.3163 +	int clockTicks = 0;
  1.3164 +	gbDmaTicks = 0;
  1.3165 +
  1.3166 +	register int opcode = 0;
  1.3167 +
  1.3168 +	u32 newmask = 0;
  1.3169 +	if (newFrame)
  1.3170 +	{
  1.3171 +		extern void VBAOnExitingFrameBoundary();
  1.3172 +		VBAOnExitingFrameBoundary();
  1.3173 +
  1.3174 +		// update joystick information
  1.3175 +		systemReadJoypads();
  1.3176 +
  1.3177 +		bool sensor = (gbRom[0x147] == 0x22);
  1.3178 +
  1.3179 +		// read joystick
  1.3180 +		if (gbSgbMode && gbSgbMultiplayer)
  1.3181 +		{
  1.3182 +			if (gbSgbFourPlayers)
  1.3183 +			{
  1.3184 +				gbJoymask[0] = systemGetJoypad(0, sensor);
  1.3185 +				gbJoymask[1] = systemGetJoypad(1, false);
  1.3186 +				gbJoymask[2] = systemGetJoypad(2, false);
  1.3187 +				gbJoymask[3] = systemGetJoypad(3, false);
  1.3188 +			}
  1.3189 +			else
  1.3190 +			{
  1.3191 +				gbJoymask[0] = systemGetJoypad(0, sensor);
  1.3192 +				gbJoymask[1] = systemGetJoypad(1, false);
  1.3193 +			}
  1.3194 +		}
  1.3195 +		else
  1.3196 +		{
  1.3197 +			gbJoymask[0] = systemGetJoypad(0, sensor);
  1.3198 +		}
  1.3199 +
  1.3200 +		// FIXME: horrible kludge
  1.3201 +		memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask));
  1.3202 +
  1.3203 +//		if (sensor)
  1.3204 +//			systemUpdateMotionSensor(0);
  1.3205 +
  1.3206 +		newmask = gbJoymask[0];
  1.3207 +		if (newmask & 0xFF)
  1.3208 +		{
  1.3209 +			gbInterrupt |= 16;
  1.3210 +		}
  1.3211 +
  1.3212 +		extButtons = (newmask >> 18);
  1.3213 +		speedup	   = (extButtons & 1) != 0;
  1.3214 +
  1.3215 +		VBAMovieResetIfRequested();
  1.3216 +
  1.3217 +		CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION);
  1.3218 +
  1.3219 +		newFrame = false;
  1.3220 +	}
  1.3221 +
  1.3222 +	for (;; )
  1.3223 +	{
  1.3224 +#ifndef FINAL_VERSION
  1.3225 +		if (systemDebug)
  1.3226 +		{
  1.3227 +			if (!(IFF & 0x80))
  1.3228 +			{
  1.3229 +				if (systemDebug > 1)
  1.3230 +				{
  1.3231 +					sprintf(gbBuffer, "PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n",
  1.3232 +					        PC.W, AF.W, BC.W, DE.W, HL.W, SP.W, IFF);
  1.3233 +				}
  1.3234 +				else
  1.3235 +				{
  1.3236 +					sprintf(gbBuffer, "PC=%04x I=%02x\n", PC.W, IFF);
  1.3237 +				}
  1.3238 +				log(gbBuffer);
  1.3239 +			}
  1.3240 +		}
  1.3241 +#endif
  1.3242 +		if (IFF & 0x80)
  1.3243 +		{
  1.3244 +			if (register_LCDC & 0x80)
  1.3245 +			{
  1.3246 +				clockTicks = gbLcdTicks;
  1.3247 +			}
  1.3248 +			else
  1.3249 +				clockTicks = 100;
  1.3250 +
  1.3251 +			if (gbLcdMode == 1 && (gbLcdLYIncrementTicks < clockTicks))
  1.3252 +				clockTicks = gbLcdLYIncrementTicks;
  1.3253 +
  1.3254 +			if (gbSerialOn && (gbSerialTicks < clockTicks))
  1.3255 +				clockTicks = gbSerialTicks;
  1.3256 +
  1.3257 +			if (gbTimerOn && (gbTimerTicks < clockTicks))
  1.3258 +				clockTicks = gbTimerTicks;
  1.3259 +
  1.3260 +			if (soundTicks && (soundTicks < clockTicks))
  1.3261 +				clockTicks = soundTicks;
  1.3262 +		}
  1.3263 +		else
  1.3264 +		{
  1.3265 +			opcode = gbReadOpcode(PC.W);
  1.3266 +			CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC);
  1.3267 +			PC.W++;
  1.3268 +
  1.3269 +			if (IFF & 0x100)
  1.3270 +			{
  1.3271 +				IFF &= 0xff;
  1.3272 +				PC.W--;
  1.3273 +			}
  1.3274 +
  1.3275 +			clockTicks = gbCycles[opcode];
  1.3276 +
  1.3277 +			switch (opcode)
  1.3278 +			{
  1.3279 +			case 0xCB:
  1.3280 +				// extended opcode
  1.3281 +				//CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC);	// is this desired?
  1.3282 +				opcode	   = gbReadOpcode(PC.W++);
  1.3283 +				clockTicks = gbCyclesCB[opcode];
  1.3284 +				switch (opcode)
  1.3285 +				{
  1.3286 +#include "gbCodesCB.h"
  1.3287 +				}
  1.3288 +				break;
  1.3289 +#include "gbCodes.h"
  1.3290 +			}
  1.3291 +		}
  1.3292 +
  1.3293 +		if (!emulating)
  1.3294 +			return;
  1.3295 +
  1.3296 +		if (gbDmaTicks)
  1.3297 +		{
  1.3298 +			clockTicks += gbDmaTicks;
  1.3299 +			gbDmaTicks	= 0;
  1.3300 +		}
  1.3301 +
  1.3302 +		if (gbSgbMode)
  1.3303 +		{
  1.3304 +			if (gbSgbPacketTimeout)
  1.3305 +			{
  1.3306 +				gbSgbPacketTimeout -= clockTicks;
  1.3307 +
  1.3308 +				if (gbSgbPacketTimeout <= 0)
  1.3309 +					gbSgbResetPacketState();
  1.3310 +			}
  1.3311 +		}
  1.3312 +
  1.3313 +		ticksToStop -= clockTicks;
  1.3314 +
  1.3315 +		// DIV register emulation
  1.3316 +		gbDivTicks -= clockTicks;
  1.3317 +		while (gbDivTicks <= 0)
  1.3318 +		{
  1.3319 +			register_DIV++;
  1.3320 +			gbDivTicks += GBDIV_CLOCK_TICKS;
  1.3321 +		}
  1.3322 +
  1.3323 +		if (register_LCDC & 0x80)
  1.3324 +		{
  1.3325 +			// LCD stuff
  1.3326 +			gbLcdTicks -= clockTicks;
  1.3327 +			if (gbLcdMode == 1)
  1.3328 +			{
  1.3329 +				// during V-BLANK,we need to increment LY at the same rate!
  1.3330 +				gbLcdLYIncrementTicks -= clockTicks;
  1.3331 +				while (gbLcdLYIncrementTicks <= 0)
  1.3332 +				{
  1.3333 +					gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS;
  1.3334 +
  1.3335 +					if (register_LY < 153)
  1.3336 +					{
  1.3337 +						register_LY++;
  1.3338 +
  1.3339 +						gbCompareLYToLYC();
  1.3340 +
  1.3341 +						if (register_LY >= 153)
  1.3342 +							gbLcdLYIncrementTicks = 6;
  1.3343 +					}
  1.3344 +					else
  1.3345 +					{
  1.3346 +						register_LY = 0x00;
  1.3347 +						// reset the window line
  1.3348 +						gbWindowLine = -1;
  1.3349 +						gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS * 2;
  1.3350 +						gbCompareLYToLYC();
  1.3351 +					}
  1.3352 +				}
  1.3353 +			}
  1.3354 +
  1.3355 +			// our counter is off, see what we need to do
  1.3356 +			while (gbLcdTicks <= 0)
  1.3357 +			{
  1.3358 +				int framesToSkip = systemFramesToSkip();
  1.3359 +
  1.3360 +				switch (gbLcdMode)
  1.3361 +				{
  1.3362 +				case 0:
  1.3363 +					// H-Blank
  1.3364 +					register_LY++;
  1.3365 +
  1.3366 +					gbCompareLYToLYC();
  1.3367 +
  1.3368 +					// check if we reached the V-Blank period
  1.3369 +					if (register_LY == 144)
  1.3370 +					{
  1.3371 +						// Yes, V-Blank
  1.3372 +						// set the LY increment counter
  1.3373 +						gbLcdLYIncrementTicks = gbLcdTicks + GBLY_INCREMENT_CLOCK_TICKS;
  1.3374 +						gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS;
  1.3375 +						gbLcdMode	= 1;
  1.3376 +						if (register_LCDC & 0x80)
  1.3377 +						{
  1.3378 +							gbInterrupt	   |= 1; // V-Blank interrupt
  1.3379 +							gbInterruptWait = 6;
  1.3380 +							if (register_STAT & 0x10)
  1.3381 +								gbInterrupt |= 2;
  1.3382 +						}
  1.3383 +
  1.3384 +						systemFrame();
  1.3385 +
  1.3386 +						++gbFrameCount;
  1.3387 +						u32 currentTime = systemGetClock();
  1.3388 +						if (currentTime - gbLastTime >= 1000)
  1.3389 +						{
  1.3390 +							systemShowSpeed(int(float(gbFrameCount) * 100000 / (float(currentTime - gbLastTime) * 60) + .5f));
  1.3391 +							gbLastTime	 = currentTime;
  1.3392 +							gbFrameCount = 0;
  1.3393 +						}
  1.3394 +
  1.3395 +						++GBSystemCounters.frameCount;
  1.3396 +						if (GBSystemCounters.lagged)
  1.3397 +						{
  1.3398 +							++GBSystemCounters.lagCount;
  1.3399 +						}
  1.3400 +						GBSystemCounters.laggedLast = GBSystemCounters.lagged;
  1.3401 +						GBSystemCounters.lagged		= true;
  1.3402 +
  1.3403 +						extern void VBAOnEnteringFrameBoundary();
  1.3404 +						VBAOnEnteringFrameBoundary();
  1.3405 +
  1.3406 +						newFrame = true;
  1.3407 +
  1.3408 +						pauseAfterFrameAdvance = systemPauseOnFrame();
  1.3409 +
  1.3410 +						if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance)
  1.3411 +						{
  1.3412 +							if (gbBorderOn)
  1.3413 +								gbSgbRenderBorder();  // clear unnecessary things on border (e.g. in-game text message)
  1.3414 +
  1.3415 +							systemRenderFrame();
  1.3416 +							gbFrameSkipCount = 0;
  1.3417 +
  1.3418 +							bool capturePressed = (extButtons & 2) != 0;
  1.3419 +							if (capturePressed && !capturePrevious)
  1.3420 +							{
  1.3421 +								captureNumber = systemScreenCapture(captureNumber);
  1.3422 +							}
  1.3423 +							capturePrevious = capturePressed && !pauseAfterFrameAdvance;
  1.3424 +						}
  1.3425 +						else
  1.3426 +						{
  1.3427 +							++gbFrameSkipCount;
  1.3428 +						}
  1.3429 +
  1.3430 +						if (pauseAfterFrameAdvance)
  1.3431 +						{
  1.3432 +							systemSetPause(true);
  1.3433 +						}
  1.3434 +					}
  1.3435 +					else
  1.3436 +					{
  1.3437 +						// go the the OAM being accessed mode
  1.3438 +						gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS;
  1.3439 +						gbLcdMode	= 2;
  1.3440 +
  1.3441 +						// only one LCD interrupt per line. may need to generalize...
  1.3442 +						if (!(register_STAT & 0x40) ||
  1.3443 +						    (register_LY != register_LYC))
  1.3444 +						{
  1.3445 +							if ((register_STAT & 0x28) == 0x20)
  1.3446 +								gbInterrupt |= 2;
  1.3447 +						}
  1.3448 +					}
  1.3449 +
  1.3450 +					break;
  1.3451 +				case 1:
  1.3452 +					// V-Blank
  1.3453 +					// next mode is OAM being accessed mode
  1.3454 +					gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS;
  1.3455 +					gbLcdMode	= 2;
  1.3456 +					if (!(register_STAT & 0x40) ||
  1.3457 +					    (register_LY != register_LYC))
  1.3458 +					{
  1.3459 +						if ((register_STAT & 0x28) == 0x20)
  1.3460 +							gbInterrupt |= 2;
  1.3461 +					}
  1.3462 +					break;
  1.3463 +				case 2:
  1.3464 +					// OAM being accessed mode
  1.3465 +
  1.3466 +					// next mode is OAM and VRAM in use
  1.3467 +					gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS;
  1.3468 +					gbLcdMode	= 3;
  1.3469 +					break;
  1.3470 +				case 3:
  1.3471 +					// OAM and VRAM in use
  1.3472 +					// next mode is H-Blank
  1.3473 +					if (register_LY < 144)
  1.3474 +					{
  1.3475 +						if (!gbSgbMask)
  1.3476 +						{
  1.3477 +							if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance)
  1.3478 +							{
  1.3479 +								gbRenderLine();
  1.3480 +								gbDrawSprites();
  1.3481 +
  1.3482 +								switch (systemColorDepth)
  1.3483 +								{
  1.3484 +								case 16:
  1.3485 +
  1.3486 +								{
  1.3487 +									u16 *dest = (u16 *)pix +
  1.3488 +									            (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1)
  1.3489 +									            + gbBorderColumnSkip;
  1.3490 +									for (int x = 0; x < 160; )
  1.3491 +									{
  1.3492 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3493 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3494 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3495 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3496 +
  1.3497 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3498 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3499 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3500 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3501 +
  1.3502 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3503 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3504 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3505 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3506 +
  1.3507 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3508 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3509 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3510 +										*dest++ = systemColorMap16[gbLineMix[x++]];
  1.3511 +									}
  1.3512 +									if (gbBorderOn)
  1.3513 +										dest += gbBorderColumnSkip;
  1.3514 +									*dest++ = 0;     // for filters that read one pixel more
  1.3515 +									break;
  1.3516 +								}
  1.3517 +								case 24:
  1.3518 +
  1.3519 +								{
  1.3520 +									u8 *dest = (u8 *)pix +
  1.3521 +									           3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) +
  1.3522 +									                gbBorderColumnSkip);
  1.3523 +									for (int x = 0; x < 160; )
  1.3524 +									{
  1.3525 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3526 +										dest += 3;
  1.3527 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3528 +										dest += 3;
  1.3529 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3530 +										dest += 3;
  1.3531 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3532 +										dest += 3;
  1.3533 +
  1.3534 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3535 +										dest += 3;
  1.3536 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3537 +										dest += 3;
  1.3538 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3539 +										dest += 3;
  1.3540 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3541 +										dest += 3;
  1.3542 +
  1.3543 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3544 +										dest += 3;
  1.3545 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3546 +										dest += 3;
  1.3547 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3548 +										dest += 3;
  1.3549 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3550 +										dest += 3;
  1.3551 +
  1.3552 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3553 +										dest += 3;
  1.3554 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3555 +										dest += 3;
  1.3556 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3557 +										dest += 3;
  1.3558 +										*((u32 *)dest) = systemColorMap32[gbLineMix[x++]];
  1.3559 +										dest += 3;
  1.3560 +									}
  1.3561 +									break;
  1.3562 +								}
  1.3563 +								case 32:
  1.3564 +
  1.3565 +								{
  1.3566 +									u32 *dest = (u32 *)pix +
  1.3567 +									            (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1)
  1.3568 +									            + gbBorderColumnSkip;
  1.3569 +									for (int x = 0; x < 160; )
  1.3570 +									{
  1.3571 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3572 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3573 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3574 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3575 +
  1.3576 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3577 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3578 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3579 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3580 +
  1.3581 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3582 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3583 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3584 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3585 +
  1.3586 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3587 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3588 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3589 +										*dest++ = systemColorMap32[gbLineMix[x++]];
  1.3590 +									}
  1.3591 +									break;
  1.3592 +								}
  1.3593 +								}
  1.3594 +							}
  1.3595 +						}
  1.3596 +					}
  1.3597 +					gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS;
  1.3598 +					gbLcdMode	= 0;
  1.3599 +					// only one LCD interrupt per line. may need to generalize...
  1.3600 +					if (!(register_STAT & 0x40) ||
  1.3601 +					    (register_LY != register_LYC))
  1.3602 +					{
  1.3603 +						if (register_STAT & 0x08)
  1.3604 +							gbInterrupt |= 2;
  1.3605 +					}
  1.3606 +					if (gbHdmaOn)
  1.3607 +					{
  1.3608 +						gbDoHdma();
  1.3609 +					}
  1.3610 +					break;
  1.3611 +				}
  1.3612 +				// mark the correct lcd mode on STAT register
  1.3613 +				register_STAT = (register_STAT & 0xfc) | gbLcdMode;
  1.3614 +			}
  1.3615 +		}
  1.3616 +
  1.3617 +		// serial emulation
  1.3618 +		if (gbSerialOn)
  1.3619 +		{
  1.3620 +#ifdef LINK_EMULATION
  1.3621 +			if (linkConnected)
  1.3622 +			{
  1.3623 +				gbSerialTicks -= clockTicks;
  1.3624 +
  1.3625 +				while (gbSerialTicks <= 0)
  1.3626 +				{
  1.3627 +					// increment number of shifted bits
  1.3628 +					gbSerialBits++;
  1.3629 +					linkProc();
  1.3630 +					if (gbSerialOn && (gbMemory[0xff02] & 1))
  1.3631 +					{
  1.3632 +						if (gbSerialBits == 8)
  1.3633 +						{
  1.3634 +							gbSerialBits	  = 0;
  1.3635 +							gbMemory[0xff01]  = 0xff;
  1.3636 +							gbMemory[0xff02] &= 0x7f;
  1.3637 +							gbSerialOn		  = 0;
  1.3638 +							gbInterrupt		 |= 8;
  1.3639 +							gbSerialTicks	  = 0;
  1.3640 +						}
  1.3641 +					}
  1.3642 +					gbSerialTicks += GBSERIAL_CLOCK_TICKS;
  1.3643 +				}
  1.3644 +			}
  1.3645 +			else
  1.3646 +			{
  1.3647 +#endif
  1.3648 +			if (gbMemory[0xff02] & 1)
  1.3649 +			{
  1.3650 +				gbSerialTicks -= clockTicks;
  1.3651 +
  1.3652 +				// overflow
  1.3653 +				while (gbSerialTicks <= 0)
  1.3654 +				{
  1.3655 +					// shift serial byte to right and put a 1 bit in its place
  1.3656 +					//      gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1);
  1.3657 +					// increment number of shifted bits
  1.3658 +					gbSerialBits++;
  1.3659 +					if (gbSerialBits == 8)
  1.3660 +					{
  1.3661 +						// end of transmission
  1.3662 +						if (gbSerialFunction)    // external device
  1.3663 +							gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]);
  1.3664 +						else
  1.3665 +							gbMemory[0xff01] = 0xff;
  1.3666 +						gbSerialTicks	  = 0;
  1.3667 +						gbMemory[0xff02] &= 0x7f;
  1.3668 +						gbSerialOn		  = 0;
  1.3669 +						gbInterrupt		 |= 8;
  1.3670 +						gbSerialBits	  = 0;
  1.3671 +					}
  1.3672 +					else
  1.3673 +						gbSerialTicks += GBSERIAL_CLOCK_TICKS;
  1.3674 +				}
  1.3675 +			}
  1.3676 +#ifdef LINK_EMULATION
  1.3677 +		}
  1.3678 +#endif
  1.3679 +		}
  1.3680 +
  1.3681 +		// timer emulation
  1.3682 +		if (gbTimerOn)
  1.3683 +		{
  1.3684 +			gbTimerTicks -= clockTicks;
  1.3685 +
  1.3686 +			while (gbTimerTicks <= 0)
  1.3687 +			{
  1.3688 +				register_TIMA++;
  1.3689 +
  1.3690 +				if (register_TIMA == 0)
  1.3691 +				{
  1.3692 +					// timer overflow!
  1.3693 +
  1.3694 +					// reload timer modulo
  1.3695 +					register_TIMA = register_TMA;
  1.3696 +
  1.3697 +					// flag interrupt
  1.3698 +					gbInterrupt |= 4;
  1.3699 +				}
  1.3700 +
  1.3701 +				gbTimerTicks += gbTimerClockTicks;
  1.3702 +			}
  1.3703 +		}
  1.3704 +
  1.3705 +		/*
  1.3706 +		   if(soundOffFlag)
  1.3707 +		   {
  1.3708 +		   if(synchronize && !speedup)
  1.3709 +		   {
  1.3710 +		   synchronizeTicks -= clockTicks;
  1.3711 +
  1.3712 +		   while(synchronizeTicks < 0)
  1.3713 +		   {
  1.3714 +		   synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS;
  1.3715 +
  1.3716 +		   DWORD now = timeGetTime();
  1.3717 +		   gbElapsedTime += (now - timeNow);
  1.3718 +
  1.3719 +		   if(gbElapsedTime < 50)
  1.3720 +		   {
  1.3721 +		   DWORD diff = 50 - gbElapsedTime;
  1.3722 +		   Sleep(diff);
  1.3723 +		   timeNow = timeGetTime();
  1.3724 +		   elapsedTime = timeNow - now - diff;
  1.3725 +		   if((int)elapsedTime < 0)
  1.3726 +		   elapsedTime = 0;
  1.3727 +		   } else
  1.3728 +		   {
  1.3729 +		   timeNow = timeGetTime();
  1.3730 +		   elapsedTime = 0;
  1.3731 +		   }
  1.3732 +		   }
  1.3733 +		   }
  1.3734 +		   }
  1.3735 +		 */
  1.3736 +
  1.3737 +		soundTicks -= clockTicks;
  1.3738 +		while (soundTicks < 0) // must be < 1 when soundtick_t is real data type
  1.3739 +		{
  1.3740 +			soundTicks += SOUND_CLOCK_TICKS;
  1.3741 +
  1.3742 +			gbSoundTick();
  1.3743 +		}
  1.3744 +
  1.3745 +		register_IF = gbInterrupt;
  1.3746 +
  1.3747 +		if (IFF & 0x20)
  1.3748 +		{
  1.3749 +			IFF &= 0xdf;
  1.3750 +			IFF |= 0x01;
  1.3751 +			gbInterruptWait = 0;
  1.3752 +		}
  1.3753 +		else if (gbInterrupt)
  1.3754 +		{
  1.3755 +			if (gbInterruptWait == 0)
  1.3756 +			{
  1.3757 +				//        gbInterruptWait = 0;
  1.3758 +
  1.3759 +				if (IFF & 0x01)
  1.3760 +				{
  1.3761 +					if ((gbInterrupt & 1) && (register_IE & 1))
  1.3762 +					{
  1.3763 +						gbVblank_interrupt();
  1.3764 +						continue;
  1.3765 +					}
  1.3766 +
  1.3767 +					if ((gbInterrupt & 2) && (register_IE & 2))
  1.3768 +					{
  1.3769 +						gbLcd_interrupt();
  1.3770 +						continue;
  1.3771 +					}
  1.3772 +
  1.3773 +					if ((gbInterrupt & 4) && (register_IE & 4))
  1.3774 +					{
  1.3775 +						gbTimer_interrupt();
  1.3776 +						continue;
  1.3777 +					}
  1.3778 +
  1.3779 +					if ((gbInterrupt & 8) && (register_IE & 8))
  1.3780 +					{
  1.3781 +						gbSerial_interrupt();
  1.3782 +						continue;
  1.3783 +					}
  1.3784 +
  1.3785 +					if ((gbInterrupt & 16) && (register_IE & 16))
  1.3786 +					{
  1.3787 +						gbJoypad_interrupt();
  1.3788 +						continue;
  1.3789 +					}
  1.3790 +				}
  1.3791 +			}
  1.3792 +			else
  1.3793 +			{
  1.3794 +				gbInterruptWait -= clockTicks;
  1.3795 +				if (gbInterruptWait < 0)
  1.3796 +					gbInterruptWait = 0;
  1.3797 +			}
  1.3798 +		}
  1.3799 +
  1.3800 +		if (useOldFrameTiming)
  1.3801 +		{
  1.3802 +			// old timing code
  1.3803 +			if (ticksToStop > 0)
  1.3804 +				continue;
  1.3805 +		}
  1.3806 +		else
  1.3807 +		{
  1.3808 +			if (!newFrame && (register_LCDC & 0x80) != 0)
  1.3809 +				continue;
  1.3810 +		}
  1.3811 +
  1.3812 +		if (!(register_LCDC & 0x80))
  1.3813 +		{
  1.3814 +			if (!useOldFrameTiming)
  1.3815 +			{
  1.3816 +				// FIXME: since register_LY can be reset to 0 by some games, frame length is variable
  1.3817 +				// and infinite loops can occurr
  1.3818 +				// for now, it IS necessary to do something on this condition or games like
  1.3819 +				// Megaman would freeze upon low-level restart interrupt sequence (Start+Select+A+B).
  1.3820 +				// the only sensible way to fix this issue is to implement the RIGHT frame timing
  1.3821 +#ifdef WANTS_INCOMPLETE_WORKAROUND
  1.3822 +				if (systemReadJoypads())
  1.3823 +				{
  1.3824 +					if (gbSgbMode && gbSgbMultiplayer)
  1.3825 +					{
  1.3826 +						if (gbSgbFourPlayers)
  1.3827 +						{
  1.3828 +							gbJoymask[0] = systemGetJoypad(0, false);
  1.3829 +							gbJoymask[1] = systemGetJoypad(1, false);
  1.3830 +							gbJoymask[2] = systemGetJoypad(2, false);
  1.3831 +							gbJoymask[3] = systemGetJoypad(3, false);
  1.3832 +						}
  1.3833 +						else
  1.3834 +						{
  1.3835 +							gbJoymask[0] = systemGetJoypad(0, false);
  1.3836 +							gbJoymask[1] = systemGetJoypad(1, false);
  1.3837 +						}
  1.3838 +					}
  1.3839 +					else
  1.3840 +					{
  1.3841 +						gbJoymask[0] = systemGetJoypad(0, false);
  1.3842 +					}
  1.3843 +				}
  1.3844 +				else
  1.3845 +					gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0;
  1.3846 +#else
  1.3847 +#endif
  1.3848 +			}
  1.3849 +		}
  1.3850 +
  1.3851 +		// makes sure frames are really divided across input sampling boundaries which occur at a constant rate
  1.3852 +		if (newFrame || useOldFrameTiming)
  1.3853 +		{
  1.3854 +///			extern void VBAOnEnteringFrameBoundary();
  1.3855 +///			VBAOnEnteringFrameBoundary();
  1.3856 +
  1.3857 +			break;
  1.3858 +		}
  1.3859 +	}
  1.3860 +}
  1.3861 +
  1.3862 +struct EmulatedSystem GBSystem =
  1.3863 +{
  1.3864 +	// emuMain
  1.3865 +	gbEmulate,
  1.3866 +	// emuReset
  1.3867 +	gbReset,
  1.3868 +	// emuCleanUp
  1.3869 +	gbCleanUp,
  1.3870 +	// emuReadBattery
  1.3871 +	gbReadBatteryFile,
  1.3872 +	// emuWriteBattery
  1.3873 +	gbWriteBatteryFile,
  1.3874 +	// emuReadBatteryFromStream
  1.3875 +	gbReadBatteryFromStream,
  1.3876 +	// emuWriteBatteryToStream
  1.3877 +	gbWriteBatteryToStream,
  1.3878 +	// emuReadState
  1.3879 +	gbReadSaveState,
  1.3880 +	// emuWriteState
  1.3881 +	gbWriteSaveState,
  1.3882 +	// emuReadStateFromStream
  1.3883 +	gbReadSaveStateFromStream,
  1.3884 +	// emuWriteStateToStream
  1.3885 +	gbWriteSaveStateToStream,
  1.3886 +	// emuReadMemState
  1.3887 +	gbReadMemSaveState,
  1.3888 +	// emuWriteMemState
  1.3889 +	gbWriteMemSaveState,
  1.3890 +	// emuWritePNG
  1.3891 +	gbWritePNGFile,
  1.3892 +	// emuWriteBMP
  1.3893 +	gbWriteBMPFile,
  1.3894 +	// emuUpdateCPSR
  1.3895 +	NULL,
  1.3896 +	// emuHasDebugger
  1.3897 +	false,
  1.3898 +	// emuCount
  1.3899 +#ifdef FINAL_VERSION
  1.3900 +	70000 / 4,
  1.3901 +#else
  1.3902 +	1000,
  1.3903 +#endif
  1.3904 +};
  1.3905 +
  1.3906 +// is there a reason to use more than one set of counters?
  1.3907 +EmulatedSystemCounters &GBSystemCounters = systemCounters;
  1.3908 +
  1.3909 +/*
  1.3910 +   EmulatedSystemCounters GBSystemCounters =
  1.3911 +   {
  1.3912 +    // frameCount
  1.3913 +    0,
  1.3914 +    // lagCount
  1.3915 +    0,
  1.3916 +    // lagged
  1.3917 +    true,
  1.3918 +    // laggedLast
  1.3919 +    true,
  1.3920 +   };
  1.3921 + */
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/gb/GB.h	Sat Mar 03 11:44:47 2012 -0600
     2.3 @@ -0,0 +1,50 @@
     2.4 +#ifndef VBA_GB_H
     2.5 +#define VBA_GB_H
     2.6 +
     2.7 +#if _MSC_VER > 1000
     2.8 +#pragma once
     2.9 +#endif // _MSC_VER > 1000
    2.10 +
    2.11 +#include "zlib.h"
    2.12 +#include "../Port.h"
    2.13 +
    2.14 +typedef union
    2.15 +{
    2.16 +	struct
    2.17 +	{
    2.18 +#ifdef WORDS_BIGENDIAN
    2.19 +		u8 B1, B0;
    2.20 +#else
    2.21 +		u8 B0, B1;
    2.22 +#endif
    2.23 +	} B;
    2.24 +	u16 W;
    2.25 +} gbRegister;
    2.26 +
    2.27 +extern bool gbLoadRom(const char *);
    2.28 +extern void gbEmulate(int);
    2.29 +extern bool gbIsGameboyRom(const char *);
    2.30 +extern void gbSoundReset();
    2.31 +extern void gbSoundSetQuality(int);
    2.32 +extern void gbReset(bool userReset = false);
    2.33 +extern void gbCleanUp();
    2.34 +extern bool gbWriteBatteryFile(const char *);
    2.35 +extern bool gbWriteBatteryFile(const char *, bool);
    2.36 +extern bool gbWriteBatteryToStream(gzFile);
    2.37 +extern bool gbReadBatteryFile(const char *);
    2.38 +extern bool gbReadBatteryFromStream(gzFile);
    2.39 +extern bool gbWriteSaveState(const char *);
    2.40 +extern bool gbWriteMemSaveState(char *, int);
    2.41 +extern bool gbReadSaveState(const char *);
    2.42 +extern bool gbReadMemSaveState(char *, int);
    2.43 +extern bool gbReadSaveStateFromStream(gzFile);
    2.44 +extern bool gbWriteSaveStateToStream(gzFile);
    2.45 +extern void gbSgbRenderBorder();
    2.46 +extern bool gbWritePNGFile(const char *);
    2.47 +extern bool gbWriteBMPFile(const char *);
    2.48 +extern bool gbReadGSASnapshot(const char *);
    2.49 +
    2.50 +extern struct EmulatedSystem GBSystem;
    2.51 +extern struct EmulatedSystemCounters &GBSystemCounters;
    2.52 +
    2.53 +#endif // VBA_GB_H
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/gb/Makefile.am	Sat Mar 03 11:44:47 2012 -0600
     3.3 @@ -0,0 +1,21 @@
     3.4 +noinst_LIBRARIES = libgb.a
     3.5 +
     3.6 +libgb_a_SOURCES = \
     3.7 +	gbCheats.cpp	\
     3.8 +	gbCheats.h	\
     3.9 +	gbCodesCB.h	\
    3.10 +	gbCodes.h	\
    3.11 +	GB.cpp		\
    3.12 +	GB.h		\
    3.13 +	gbDis.cpp	\
    3.14 +	gbGfx.cpp	\
    3.15 +	gbGlobals.cpp	\
    3.16 +	gbGlobals.h	\
    3.17 +	gbMemory.cpp	\
    3.18 +	gbMemory.h	\
    3.19 +	gbPrinter.cpp	\
    3.20 +	gbPrinter.h	\
    3.21 +	gbSGB.cpp	\
    3.22 +	gbSGB.h		\
    3.23 +	gbSound.cpp	\
    3.24 +	gbSound.h
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/gb/gbCheats.cpp	Sat Mar 03 11:44:47 2012 -0600
     4.3 @@ -0,0 +1,477 @@
     4.4 +#include <cstdio>
     4.5 +#include <cstdlib>
     4.6 +#include <cctype>
     4.7 +#include <cstring>
     4.8 +
     4.9 +#include "../NLS.h"
    4.10 +#include "../common/System.h"
    4.11 +#include "../common/Util.h"
    4.12 +
    4.13 +#include "gbCheats.h"
    4.14 +#include "gbGlobals.h"
    4.15 +
    4.16 +gbCheat gbCheatList[100];
    4.17 +int     gbCheatNumber = 0;
    4.18 +bool    gbCheatMap[0x10000];
    4.19 +
    4.20 +extern bool8 cheatsEnabled;
    4.21 +
    4.22 +#define GBCHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9'))
    4.23 +#define GBCHEAT_HEX_VALUE(a) ((a) >= 'A' ? (a) - 'A' + 10 : (a) - '0')
    4.24 +
    4.25 +void gbCheatUpdateMap()
    4.26 +{
    4.27 +	memset(gbCheatMap, 0, 0x10000);
    4.28 +
    4.29 +	for (int i = 0; i < gbCheatNumber; i++)
    4.30 +	{
    4.31 +		if (gbCheatList[i].enabled)
    4.32 +			gbCheatMap[gbCheatList[i].address] = true;
    4.33 +	}
    4.34 +}
    4.35 +
    4.36 +void gbCheatsSaveGame(gzFile gzFile)
    4.37 +{
    4.38 +	utilWriteInt(gzFile, gbCheatNumber);
    4.39 +	if (gbCheatNumber)
    4.40 +		utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
    4.41 +}
    4.42 +
    4.43 +void gbCheatsReadGame(gzFile gzFile, int version)
    4.44 +{
    4.45 +	if (version <= 8)
    4.46 +	{
    4.47 +		int gbGgOn = utilReadInt(gzFile);
    4.48 +
    4.49 +		if (gbGgOn)
    4.50 +		{
    4.51 +			int       n = utilReadInt(gzFile);
    4.52 +			gbXxCheat tmpCheat;
    4.53 +			for (int i = 0; i < n; i++)
    4.54 +			{
    4.55 +				utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));
    4.56 +				gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
    4.57 +			}
    4.58 +		}
    4.59 +
    4.60 +		int gbGsOn = utilReadInt(gzFile);
    4.61 +
    4.62 +		if (gbGsOn)
    4.63 +		{
    4.64 +			int       n = utilReadInt(gzFile);
    4.65 +			gbXxCheat tmpCheat;
    4.66 +			for (int i = 0; i < n; i++)
    4.67 +			{
    4.68 +				utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));
    4.69 +				gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
    4.70 +			}
    4.71 +		}
    4.72 +	}
    4.73 +	else
    4.74 +	{
    4.75 +		gbCheatNumber = utilReadInt(gzFile);
    4.76 +
    4.77 +		if (gbCheatNumber)
    4.78 +		{
    4.79 +			utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
    4.80 +		}
    4.81 +	}
    4.82 +
    4.83 +	gbCheatUpdateMap();
    4.84 +}
    4.85 +
    4.86 +void gbCheatsSaveCheatList(const char *file)
    4.87 +{
    4.88 +	if (gbCheatNumber == 0)
    4.89 +		return;
    4.90 +	FILE *f = fopen(file, "wb");
    4.91 +	if (f == NULL)
    4.92 +		return;
    4.93 +	int version = 1;
    4.94 +	fwrite(&version, 1, sizeof(version), f);
    4.95 +	int type = 1;
    4.96 +	fwrite(&type, 1, sizeof(type), f);
    4.97 +	fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f);
    4.98 +	fwrite(gbCheatList, 1, sizeof(gbCheatList), f);
    4.99 +	fclose(f);
   4.100 +}
   4.101 +
   4.102 +bool gbCheatsLoadCheatList(const char *file)
   4.103 +{
   4.104 +	gbCheatNumber = 0;
   4.105 +
   4.106 +	gbCheatUpdateMap();
   4.107 +
   4.108 +	int count = 0;
   4.109 +
   4.110 +	FILE *f = fopen(file, "rb");
   4.111 +
   4.112 +	if (f == NULL)
   4.113 +		return false;
   4.114 +
   4.115 +	int version = 0;
   4.116 +
   4.117 +	if (fread(&version, 1, sizeof(version), f) != sizeof(version))
   4.118 +	{
   4.119 +		fclose(f);
   4.120 +		return false;
   4.121 +	}
   4.122 +
   4.123 +	if (version != 1)
   4.124 +	{
   4.125 +		systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,
   4.126 +		              N_("Unsupported cheat list version %d"), version);
   4.127 +		fclose(f);
   4.128 +		return false;
   4.129 +	}
   4.130 +
   4.131 +	int type = 0;
   4.132 +	if (fread(&type, 1, sizeof(type), f) != sizeof(type))
   4.133 +	{
   4.134 +		fclose(f);
   4.135 +		return false;
   4.136 +	}
   4.137 +
   4.138 +	if (type != 1)
   4.139 +	{
   4.140 +		systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,
   4.141 +		              N_("Unsupported cheat list type %d"), type);
   4.142 +		fclose(f);
   4.143 +		return false;
   4.144 +	}
   4.145 +
   4.146 +	if (fread(&count, 1, sizeof(count), f) != sizeof(count))
   4.147 +	{
   4.148 +		fclose(f);
   4.149 +		return false;
   4.150 +	}
   4.151 +
   4.152 +	if (fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList))
   4.153 +	{
   4.154 +		fclose(f);
   4.155 +		return false;
   4.156 +	}
   4.157 +
   4.158 +	fclose(f);
   4.159 +	gbCheatNumber = count;
   4.160 +	gbCheatUpdateMap();
   4.161 +
   4.162 +	return true;
   4.163 +}
   4.164 +
   4.165 +bool gbVerifyGsCode(const char *code)
   4.166 +{
   4.167 +	int len = strlen(code);
   4.168 +
   4.169 +	if (len == 0)
   4.170 +		return true;
   4.171 +
   4.172 +	if (len != 8)
   4.173 +		return false;
   4.174 +
   4.175 +	for (int i = 0; i < 8; i++)
   4.176 +		if (!GBCHEAT_IS_HEX(code[i]))
   4.177 +			return false;
   4.178 +
   4.179 +	int address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
   4.180 +	              GBCHEAT_HEX_VALUE(code[7]) << 8 |
   4.181 +	              GBCHEAT_HEX_VALUE(code[4]) << 4 |
   4.182 +	              GBCHEAT_HEX_VALUE(code[5]);
   4.183 +
   4.184 +	if (address < 0xa000 ||
   4.185 +	    address > 0xdfff)
   4.186 +		return false;
   4.187 +
   4.188 +	return true;
   4.189 +}
   4.190 +
   4.191 +void gbAddGsCheat(const char *code, const char *desc)
   4.192 +{
   4.193 +	if (gbCheatNumber > 99)
   4.194 +	{
   4.195 +		systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
   4.196 +		              N_("Maximum number of cheats reached."));
   4.197 +		return;
   4.198 +	}
   4.199 +
   4.200 +	if (!gbVerifyGsCode(code))
   4.201 +	{
   4.202 +		systemMessage(MSG_INVALID_GAMESHARK_CODE,
   4.203 +		              N_("Invalid GameShark code: %s"), code);
   4.204 +		return;
   4.205 +	}
   4.206 +
   4.207 +	int i = gbCheatNumber;
   4.208 +
   4.209 +	strcpy(gbCheatList[i].cheatCode, code);
   4.210 +	strcpy(gbCheatList[i].cheatDesc, desc);
   4.211 +
   4.212 +	gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 |
   4.213 +	                      GBCHEAT_HEX_VALUE(code[1]);
   4.214 +
   4.215 +	gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 |
   4.216 +	                       GBCHEAT_HEX_VALUE(code[3]);
   4.217 +
   4.218 +	gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
   4.219 +	                         GBCHEAT_HEX_VALUE(code[7]) << 8 |
   4.220 +	                         GBCHEAT_HEX_VALUE(code[4]) << 4 |
   4.221 +	                         GBCHEAT_HEX_VALUE(code[5]);
   4.222 +
   4.223 +	gbCheatList[i].compare = 0;
   4.224 +
   4.225 +	gbCheatList[i].enabled = true;
   4.226 +
   4.227 +	gbCheatMap[gbCheatList[i].address] = true;
   4.228 +
   4.229 +	gbCheatNumber++;
   4.230 +}
   4.231 +
   4.232 +bool gbVerifyGgCode(const char *code)
   4.233 +{
   4.234 +	int len = strlen(code);
   4.235 +
   4.236 +	if (len != 11 &&
   4.237 +	    len != 7 &&
   4.238 +	    len != 6 &&
   4.239 +	    len != 0)
   4.240 +		return false;
   4.241 +
   4.242 +	if (len == 0)
   4.243 +		return true;
   4.244 +
   4.245 +	if (!GBCHEAT_IS_HEX(code[0]))
   4.246 +		return false;
   4.247 +	if (!GBCHEAT_IS_HEX(code[1]))
   4.248 +		return false;
   4.249 +	if (!GBCHEAT_IS_HEX(code[2]))
   4.250 +		return false;
   4.251 +	if (code[3] != '-')
   4.252 +		return false;
   4.253 +	if (!GBCHEAT_IS_HEX(code[4]))
   4.254 +		return false;
   4.255 +	if (!GBCHEAT_IS_HEX(code[5]))
   4.256 +		return false;
   4.257 +	if (!GBCHEAT_IS_HEX(code[6]))
   4.258 +		return false;
   4.259 +	if (code[7] != 0)
   4.260 +	{
   4.261 +		if (code[7] != '-')
   4.262 +			return false;
   4.263 +		if (code[8] != 0)
   4.264 +		{
   4.265 +			if (!GBCHEAT_IS_HEX(code[8]))
   4.266 +				return false;
   4.267 +			if (!GBCHEAT_IS_HEX(code[9]))
   4.268 +				return false;
   4.269 +			if (!GBCHEAT_IS_HEX(code[10]))
   4.270 +				return false;
   4.271 +		}
   4.272 +	}
   4.273 +
   4.274 +	//  int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
   4.275 +	//    GBCHEAT_HEX_VALUE(code[1]);
   4.276 +
   4.277 +	int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
   4.278 +	              (GBCHEAT_HEX_VALUE(code[4]) << 4) +
   4.279 +	              (GBCHEAT_HEX_VALUE(code[5])) +
   4.280 +	              ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
   4.281 +
   4.282 +	if (address >= 0x8000 && address <= 0x9fff)
   4.283 +		return false;
   4.284 +
   4.285 +	if (address >= 0xc000)
   4.286 +		return false;
   4.287 +
   4.288 +	if (code[7] == 0 || code[8] == '0')
   4.289 +		return true;
   4.290 +
   4.291 +	int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
   4.292 +	              (GBCHEAT_HEX_VALUE(code[10]));
   4.293 +	compare  = compare ^ 0xff;
   4.294 +	compare  = (compare >> 2) | ((compare << 6) & 0xc0);
   4.295 +	compare ^= 0x45;
   4.296 +
   4.297 +	int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9]));
   4.298 +
   4.299 +	if (cloak >= 1 && cloak <= 7)
   4.300 +		return false;
   4.301 +
   4.302 +	return true;
   4.303 +}
   4.304 +
   4.305 +void gbAddGgCheat(const char *code, const char *desc)
   4.306 +{
   4.307 +	if (gbCheatNumber > 99)
   4.308 +	{
   4.309 +		systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
   4.310 +		              N_("Maximum number of cheats reached."));
   4.311 +		return;
   4.312 +	}
   4.313 +
   4.314 +	if (!gbVerifyGgCode(code))
   4.315 +	{
   4.316 +		systemMessage(MSG_INVALID_GAMEGENIE_CODE,
   4.317 +		              N_("Invalid GameGenie code: %s"), code);
   4.318 +		return;
   4.319 +	}
   4.320 +
   4.321 +	int i = gbCheatNumber;
   4.322 +
   4.323 +	int len = strlen(code);
   4.324 +
   4.325 +	strcpy(gbCheatList[i].cheatCode, code);
   4.326 +	strcpy(gbCheatList[i].cheatDesc, desc);
   4.327 +
   4.328 +	gbCheatList[i].code  = 1;
   4.329 +	gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
   4.330 +	                       GBCHEAT_HEX_VALUE(code[1]);
   4.331 +
   4.332 +	gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
   4.333 +	                         (GBCHEAT_HEX_VALUE(code[4]) << 4) +
   4.334 +	                         (GBCHEAT_HEX_VALUE(code[5])) +
   4.335 +	                         ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
   4.336 +
   4.337 +	gbCheatList[i].compare = 0;
   4.338 +
   4.339 +	if (len != 7 && len != 8)
   4.340 +	{
   4.341 +		int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
   4.342 +		              (GBCHEAT_HEX_VALUE(code[10]));
   4.343 +		compare  = compare ^ 0xff;
   4.344 +		compare  = (compare >> 2) | ((compare << 6) & 0xc0);
   4.345 +		compare ^= 0x45;
   4.346 +
   4.347 +		gbCheatList[i].compare = compare;
   4.348 +		gbCheatList[i].code    = 0;
   4.349 +	}
   4.350 +
   4.351 +	gbCheatList[i].enabled = true;
   4.352 +
   4.353 +	gbCheatMap[gbCheatList[i].address] = true;
   4.354 +
   4.355 +	gbCheatNumber++;
   4.356 +}
   4.357 +
   4.358 +void gbCheatRemove(int i)
   4.359 +{
   4.360 +	if (i < 0 || i >= gbCheatNumber)
   4.361 +	{
   4.362 +		systemMessage(MSG_INVALID_CHEAT_TO_REMOVE,
   4.363 +		              N_("Invalid cheat to remove %d"), i);
   4.364 +		return;
   4.365 +	}
   4.366 +
   4.367 +	if ((i+1) <  gbCheatNumber)
   4.368 +	{
   4.369 +		memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)*
   4.370 +		       (gbCheatNumber-i-1));
   4.371 +	}
   4.372 +
   4.373 +	gbCheatNumber--;
   4.374 +
   4.375 +	gbCheatUpdateMap();
   4.376 +}
   4.377 +
   4.378 +void gbCheatRemoveAll()
   4.379 +{
   4.380 +	gbCheatNumber = 0;
   4.381 +	gbCheatUpdateMap();
   4.382 +}
   4.383 +
   4.384 +void gbCheatEnable(int i)
   4.385 +{
   4.386 +	if (i >= 0 && i < gbCheatNumber)
   4.387 +	{
   4.388 +		if (!gbCheatList[i].enabled)
   4.389 +		{
   4.390 +			gbCheatList[i].enabled = true;
   4.391 +			gbCheatUpdateMap();
   4.392 +		}
   4.393 +	}
   4.394 +}
   4.395 +
   4.396 +void gbCheatDisable(int i)
   4.397 +{
   4.398 +	if (i >= 0 && i < gbCheatNumber)
   4.399 +	{
   4.400 +		if (gbCheatList[i].enabled)
   4.401 +		{
   4.402 +			gbCheatList[i].enabled = false;
   4.403 +			gbCheatUpdateMap();
   4.404 +		}
   4.405 +	}
   4.406 +}
   4.407 +
   4.408 +bool gbCheatReadGSCodeFile(const char *fileName)
   4.409 +{
   4.410 +	FILE *file = fopen(fileName, "rb");
   4.411 +
   4.412 +	if (!file)
   4.413 +		return false;
   4.414 +
   4.415 +	fseek(file, 0x18, SEEK_SET);
   4.416 +	int count = 0;
   4.417 +	fread(&count, 1, 2, file);
   4.418 +	int dummy = 0;
   4.419 +	gbCheatRemoveAll();
   4.420 +	char desc[13];
   4.421 +	char code[9];
   4.422 +	int  i;
   4.423 +	for (i = 0; i < count; i++)
   4.424 +	{
   4.425 +		fread(&dummy, 1, 2, file);
   4.426 +		fread(desc, 1, 12, file);
   4.427 +		desc[12] = 0;
   4.428 +		fread(code, 1, 8, file);
   4.429 +		code[8] = 0;
   4.430 +		gbAddGsCheat(code, desc);
   4.431 +	}
   4.432 +
   4.433 +	for (i = 0; i < gbCheatNumber; i++)
   4.434 +		gbCheatDisable(i);
   4.435 +
   4.436 +	fclose(file);
   4.437 +	return true;
   4.438 +}
   4.439 +
   4.440 +u8 gbCheatRead(u16 address)
   4.441 +{
   4.442 +	if (!cheatsEnabled)
   4.443 +		return gbReadMemoryQuick(address);
   4.444 +
   4.445 +	for (int i = 0; i < gbCheatNumber; i++)
   4.446 +	{
   4.447 +		if (gbCheatList[i].enabled && gbCheatList[i].address == address)
   4.448 +		{
   4.449 +			switch (gbCheatList[i].code)
   4.450 +			{
   4.451 +			case 0x100: // GameGenie support
   4.452 +				if (gbReadMemoryQuick(address) == gbCheatList[i].compare)
   4.453 +					return gbCheatList[i].value;
   4.454 +				break;
   4.455 +			case 0x00:
   4.456 +			case 0x01:
   4.457 +			case 0x80:
   4.458 +				return gbCheatList[i].value;
   4.459 +			case 0x90:
   4.460 +			case 0x91:
   4.461 +			case 0x92:
   4.462 +			case 0x93:
   4.463 +			case 0x94:
   4.464 +			case 0x95:
   4.465 +			case 0x96:
   4.466 +			case 0x97:
   4.467 +				if (address >= 0xd000 && address < 0xe000)
   4.468 +				{
   4.469 +					if (((gbMemoryMap[0x0d] - gbWram)/0x1000) ==
   4.470 +					    (gbCheatList[i].code - 0x90))
   4.471 +						return gbCheatList[i].value;
   4.472 +				}
   4.473 +				else
   4.474 +					return gbCheatList[i].value;
   4.475 +			}
   4.476 +		}
   4.477 +	}
   4.478 +	return gbReadMemoryQuick(address);
   4.479 +}
   4.480 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/gb/gbCheats.h	Sat Mar 03 11:44:47 2012 -0600
     5.3 @@ -0,0 +1,44 @@
     5.4 +#ifndef VBA_GB_CHEATS_H
     5.5 +#define VBA_GB_CHEATS_H
     5.6 +
     5.7 +#if _MSC_VER > 1000
     5.8 +#pragma once
     5.9 +#endif // _MSC_VER > 1000
    5.10 +
    5.11 +struct gbXxCheat
    5.12 +{
    5.13 +	char cheatDesc[100];
    5.14 +	char cheatCode[20];
    5.15 +};
    5.16 +
    5.17 +struct gbCheat
    5.18 +{
    5.19 +	char cheatCode[20];
    5.20 +	char cheatDesc[32];
    5.21 +	u16  address;
    5.22 +	int  code;
    5.23 +	u8   compare;
    5.24 +	u8   value;
    5.25 +	bool enabled;
    5.26 +};
    5.27 +
    5.28 +extern void gbCheatsSaveGame(gzFile);
    5.29 +extern void gbCheatsReadGame(gzFile, int);
    5.30 +extern void gbCheatsSaveCheatList(const char *);
    5.31 +extern bool gbCheatsLoadCheatList(const char *);
    5.32 +extern bool gbCheatReadGSCodeFile(const char *);
    5.33 +
    5.34 +extern void gbAddGsCheat(const char *, const char *);
    5.35 +extern void gbAddGgCheat(const char *, const char *);
    5.36 +extern void gbCheatRemove(int);
    5.37 +extern void gbCheatRemoveAll();
    5.38 +extern void gbCheatEnable(int);
    5.39 +extern void gbCheatDisable(int);
    5.40 +extern u8 gbCheatRead(u16);
    5.41 +
    5.42 +extern int     gbCheatNumber;
    5.43 +extern gbCheat gbCheatList[100];
    5.44 +extern bool    gbCheatMap[0x10000];
    5.45 +
    5.46 +#endif // VBA_GB_CHEATS_H
    5.47 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/gb/gbCodes.h	Sat Mar 03 11:44:47 2012 -0600
     6.3 @@ -0,0 +1,1388 @@
     6.4 + case 0x00: 
     6.5 +   // NOP
     6.6 +   break;
     6.7 + case 0x01: 
     6.8 +   // LD BC, NNNN
     6.9 +   BC.B.B0=gbReadMemory(PC.W++);
    6.10 +   BC.B.B1=gbReadMemory(PC.W++);
    6.11 +   break;
    6.12 + case 0x02:
    6.13 +   // LD (BC),A
    6.14 +   gbWriteMemory(BC.W,AF.B.B1);
    6.15 +   break;
    6.16 + case 0x03:
    6.17 +   // INC BC
    6.18 +   BC.W++;
    6.19 +   break;
    6.20 + case 0x04: 
    6.21 +   // INC B
    6.22 +   BC.B.B1++; 
    6.23 +   AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B1]| (BC.B.B1&0x0F? 0:H_FLAG);
    6.24 +   break;
    6.25 + case 0x05:
    6.26 +   // DEC B
    6.27 +   BC.B.B1--; 
    6.28 +   AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B1]|
    6.29 +     ((BC.B.B1&0x0F)==0x0F? H_FLAG:0);
    6.30 +   break;
    6.31 + case 0x06:
    6.32 +   // LD B, NN
    6.33 +   BC.B.B1=gbReadOpcode(PC.W++);
    6.34 +   break;
    6.35 + case 0x07:
    6.36 +   // RLCA
    6.37 +   tempValue=AF.B.B1&0x80? C_FLAG:0;
    6.38 +   AF.B.B1=((AF.B.B1<<1)|(AF.B.B1>>7)) & 0xFF;
    6.39 +   AF.B.B0=tempValue;
    6.40 +   break;
    6.41 + case 0x08:
    6.42 +   // LD (NNNN), SP
    6.43 +   tempRegister.B.B0=gbReadOpcode(PC.W++);
    6.44 +   tempRegister.B.B1=gbReadOpcode(PC.W++);
    6.45 +   gbWriteMemory(tempRegister.W++,SP.B.B0);
    6.46 +   gbWriteMemory(tempRegister.W,SP.B.B1);
    6.47 +   break;
    6.48 + case 0x09:
    6.49 +   // ADD HL,BC
    6.50 +   tempRegister.W=(HL.W+BC.W)&0xFFFF;
    6.51 +   AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^BC.W^tempRegister.W)&0x1000? H_FLAG:0)|
    6.52 +     (((long)HL.W+(long)BC.W)&0x10000? C_FLAG:0);
    6.53 +   HL.W=tempRegister.W;
    6.54 +   break;
    6.55 + case 0x0a:
    6.56 +   // LD A,(BC)
    6.57 +   AF.B.B1=gbReadMemory(BC.W);
    6.58 +   break;
    6.59 + case 0x0b:
    6.60 +   // DEC BC
    6.61 +   BC.W--;
    6.62 +   break;   
    6.63 + case 0x0c:
    6.64 +   // INC C
    6.65 +   BC.B.B0++;
    6.66 +   AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B0]| (BC.B.B0&0x0F? 0:H_FLAG);
    6.67 +   break;
    6.68 + case 0x0d:
    6.69 +   // DEC C
    6.70 +   BC.B.B0--;
    6.71 +   AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B0]|
    6.72 +     ((BC.B.B0&0x0F)==0x0F? H_FLAG:0);
    6.73 +   break;   
    6.74 + case 0x0e:
    6.75 +   // LD C, NN
    6.76 +   BC.B.B0=gbReadOpcode(PC.W++);
    6.77 +   break;
    6.78 + case 0x0f:
    6.79 +   // RRCA
    6.80 +   tempValue=AF.B.B1&0x01;
    6.81 +   AF.B.B1=(AF.B.B1>>1)|(tempValue? 0x80:0);
    6.82 +   AF.B.B0=(tempValue<<4);
    6.83 +   break;
    6.84 + case 0x10:
    6.85 +   // STOP
    6.86 +   opcode = gbReadOpcode(PC.W++);
    6.87 +   if(gbCgbMode) {
    6.88 +     if(gbReadMemoryQuick(0xff4d) & 1) {
    6.89 +       gbSpeedSwitch();
    6.90 +       
    6.91 +       if(gbSpeed == 0)
    6.92 +         gbWriteMemoryQuick(0xff4d, 0x00);
    6.93 +       else
    6.94 +         gbWriteMemoryQuick(0xff4d, 0x80);
    6.95 +     }
    6.96 +   }
    6.97 +   break;
    6.98 + case 0x11:
    6.99 +   // LD DE, NNNN
   6.100 +   DE.B.B0=gbReadMemory(PC.W++);
   6.101 +   DE.B.B1=gbReadMemory(PC.W++);
   6.102 +   break;
   6.103 + case 0x12:
   6.104 +   // LD (DE),A
   6.105 +   gbWriteMemory(DE.W,AF.B.B1);
   6.106 +   break;
   6.107 + case 0x13:
   6.108 +   // INC DE
   6.109 +   DE.W++;
   6.110 +   break;
   6.111 + case 0x14:
   6.112 +   // INC D
   6.113 +   DE.B.B1++;
   6.114 +   AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B1]| (DE.B.B1&0x0F? 0:H_FLAG);
   6.115 +   break;
   6.116 + case 0x15:
   6.117 +   // DEC D
   6.118 +   DE.B.B1--;
   6.119 +   AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B1]|
   6.120 +     ((DE.B.B1&0x0F)==0x0F? H_FLAG:0);
   6.121 +   break;
   6.122 + case 0x16:
   6.123 +   //  LD D,NN
   6.124 +   DE.B.B1=gbReadOpcode(PC.W++);
   6.125 +   break;
   6.126 + case 0x17:
   6.127 +   // RLA
   6.128 +   tempValue=AF.B.B1&0x80? C_FLAG:0;
   6.129 +   AF.B.B1=((AF.B.B1<<1)|((AF.B.B0&C_FLAG)>>4)) & 0xFF;
   6.130 +   AF.B.B0=tempValue;
   6.131 +   break;
   6.132 + case 0x18:
   6.133 +   // JR NN
   6.134 +   PC.W+=(s8)gbReadMemory(PC.W)+1;
   6.135 +   break;
   6.136 + case 0x19:
   6.137 +   // ADD HL,DE
   6.138 +   tempRegister.W=(HL.W+DE.W)&0xFFFF;
   6.139 +   AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^DE.W^tempRegister.W)&0x1000? H_FLAG:0)|
   6.140 +     (((long)HL.W+(long)DE.W)&0x10000? C_FLAG:0);
   6.141 +   HL.W=tempRegister.W;
   6.142 +   break;
   6.143 + case 0x1a:
   6.144 +   // LD A,(DE)
   6.145 +   AF.B.B1=gbReadMemory(DE.W);
   6.146 +   break;   
   6.147 + case 0x1b:
   6.148 +   // DEC DE
   6.149 +   DE.W--;
   6.150 +   break;
   6.151 + case 0x1c:
   6.152 +   // INC E
   6.153 +   DE.B.B0++;
   6.154 +   AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B0]| (DE.B.B0&0x0F? 0:H_FLAG);
   6.155 +   break;
   6.156 + case 0x1d:
   6.157 +   // DEC E
   6.158 +   DE.B.B0--;
   6.159 +   AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B0]|
   6.160 +     ((DE.B.B0&0x0F)==0x0F? H_FLAG:0);
   6.161 +   break;
   6.162 + case 0x1e:
   6.163 +   // LD E,NN
   6.164 +   DE.B.B0=gbReadOpcode(PC.W++);
   6.165 +   break;   
   6.166 + case 0x1f:
   6.167 +   // RRA
   6.168 +   tempValue=AF.B.B1&0x01;
   6.169 +   AF.B.B1=(AF.B.B1>>1)|(AF.B.B0&C_FLAG? 0x80:0);
   6.170 +   AF.B.B0=(tempValue<<4);
   6.171 +   break;
   6.172 + case 0x20:
   6.173 +   // JR NZ,NN
   6.174 +   if(AF.B.B0&Z_FLAG)
   6.175 +     PC.W++;
   6.176 +   else {
   6.177 +     PC.W+=(s8)gbReadMemory(PC.W)+1;
   6.178 +     clockTicks++;
   6.179 +   }
   6.180 +   break;
   6.181 + case 0x21:
   6.182 +   // LD HL,NNNN
   6.183 +   HL.B.B0=gbReadMemory(PC.W++);
   6.184 +   HL.B.B1=gbReadMemory(PC.W++);
   6.185 +   break;   
   6.186 + case 0x22:
   6.187 +   // LDI (HL),A
   6.188 +   gbWriteMemory(HL.W++,AF.B.B1);
   6.189 +   break;
   6.190 + case 0x23:
   6.191 +   // INC HL
   6.192 +   HL.W++;
   6.193 +   break;
   6.194 + case 0x24:
   6.195 +   // INC H
   6.196 +   HL.B.B1++;
   6.197 +   AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B1]| (HL.B.B1&0x0F? 0:H_FLAG);
   6.198 +   break;
   6.199 + case 0x25:
   6.200 +   // DEC H
   6.201 +   HL.B.B1--;
   6.202 +   AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B1]|
   6.203 +     ((HL.B.B1&0x0F)==0x0F? H_FLAG:0);
   6.204 +   break;
   6.205 + case 0x26:
   6.206 +   // LD H,NN
   6.207 +   HL.B.B1=gbReadOpcode(PC.W++);
   6.208 +   break;
   6.209 + case 0x27:
   6.210 +   // DAA
   6.211 +   tempRegister.W=AF.B.B1;
   6.212 +   if(AF.B.B0&C_FLAG) tempRegister.W|=256;
   6.213 +   if(AF.B.B0&H_FLAG) tempRegister.W|=512;
   6.214 +   if(AF.B.B0&N_FLAG) tempRegister.W|=1024;
   6.215 +   AF.W=DAATable[tempRegister.W];
   6.216 +   break;
   6.217 + case 0x28:
   6.218 +   // JR Z,NN
   6.219 +   if(AF.B.B0&Z_FLAG) {
   6.220 +     PC.W+=(s8)gbReadMemory(PC.W)+1;
   6.221 +     clockTicks++;
   6.222 +   } else
   6.223 +     PC.W++;
   6.224 +   break;
   6.225 + case 0x29:
   6.226 +   // ADD HL,HL
   6.227 +   tempRegister.W=(HL.W+HL.W)&0xFFFF; AF.B.B0= (AF.B.B0 & Z_FLAG)|
   6.228 +                             ((HL.W^HL.W^tempRegister.W)&0x1000? H_FLAG:0)|
   6.229 +                             (((long)HL.W+(long)HL.W)&0x10000? C_FLAG:0);
   6.230 +   HL.W=tempRegister.W;
   6.231 +   break;
   6.232 + case 0x2a:
   6.233 +   // LDI A,(HL)
   6.234 +   AF.B.B1 = gbReadMemory(HL.W++);
   6.235 +   break;
   6.236 + case 0x2b:
   6.237 +   // DEC HL
   6.238 +   HL.W--;
   6.239 +   break;   
   6.240 + case 0x2c:
   6.241 +   // INC L
   6.242 +   HL.B.B0++;
   6.243 +   AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B0]| (HL.B.B0&0x0F? 0:H_FLAG);
   6.244 +   break;
   6.245 + case 0x2d:
   6.246 +   // DEC L
   6.247 +   HL.B.B0--;
   6.248 +   AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B0]|
   6.249 +     ((HL.B.B0&0x0F)==0x0F? H_FLAG:0);
   6.250 +   break;
   6.251 + case 0x2e:
   6.252 +   // LD L,NN
   6.253 +   HL.B.B0=gbReadOpcode(PC.W++);
   6.254 +   break;   
   6.255 + case 0x2f:
   6.256 +   // CPL
   6.257 +   AF.B.B1 ^= 255;
   6.258 +   AF.B.B0|=N_FLAG|H_FLAG;
   6.259 +   break;
   6.260 + case 0x30:
   6.261 +   // JR NC,NN
   6.262 +   if(AF.B.B0&C_FLAG)
   6.263 +     PC.W++;
   6.264 +   else {
   6.265 +     PC.W+=(s8)gbReadMemory(PC.W)+1;
   6.266 +     clockTicks++;
   6.267 +   }
   6.268 +   break;
   6.269 + case 0x31:
   6.270 +   // LD SP,NNNN
   6.271 +   SP.B.B0=gbReadMemory(PC.W++);
   6.272 +   SP.B.B1=gbReadMemory(PC.W++);
   6.273 +   break;
   6.274 + case 0x32:
   6.275 +   // LDD (HL),A
   6.276 +   gbWriteMemory(HL.W--,AF.B.B1);
   6.277 +   break;
   6.278 + case 0x33:
   6.279 +   // INC SP
   6.280 +   SP.W++;
   6.281 +   break;
   6.282 + case 0x34:
   6.283 +   // INC (HL)
   6.284 +   tempValue=(gbReadMemory(HL.W)+1) & 0xFF;
   6.285 +   AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[tempValue]| (tempValue&0x0F? 0:H_FLAG);
   6.286 +   gbWriteMemory(HL.W,tempValue);
   6.287 +   break;
   6.288 + case 0x35:
   6.289 +   // DEC (HL)
   6.290 +   tempValue=(gbReadMemory(HL.W)-1) & 0xFF;
   6.291 +   AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[tempValue]|
   6.292 +     ((tempValue&0x0F)==0x0F? H_FLAG:0);gbWriteMemory(HL.W,tempValue);
   6.293 +   break;
   6.294 + case 0x36:
   6.295 +   // LD (HL),NN
   6.296 +   gbWriteMemory(HL.W,gbReadOpcode(PC.W++));
   6.297 +   break;
   6.298 + case 0x37:
   6.299 +   // SCF
   6.300 +   AF.B.B0 = AF.B.B0 & Z_FLAG | C_FLAG;
   6.301 +   break;   
   6.302 +case 0x38:
   6.303 +  // JR C,NN
   6.304 +  if(AF.B.B0&C_FLAG) {
   6.305 +    PC.W+=(s8)gbReadMemory(PC.W)+1;
   6.306 +    clockTicks ++;
   6.307 +  } else
   6.308 +    PC.W++;
   6.309 +  break;
   6.310 + case 0x39:
   6.311 +   // ADD HL,SP
   6.312 +   tempRegister.W=(HL.W+SP.W)&0xFFFF;
   6.313 +   AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^SP.W^tempRegister.W)&0x1000? H_FLAG:0)|
   6.314 +     (((long)HL.W+(long)SP.W)&0x10000? C_FLAG:0);
   6.315 +   HL.W=tempRegister.W;
   6.316 +   break;
   6.317 + case 0x3a:
   6.318 +   // LDD A,(HL)
   6.319 +   AF.B.B1 = gbReadMemory(HL.W--);
   6.320 +   break;
   6.321 + case 0x3b:
   6.322 +   // DEC SP
   6.323 +   SP.W--;
   6.324 +   break;
   6.325 + case 0x3c:
   6.326 +   // INC A
   6.327 +   AF.B.B1++;
   6.328 +   AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[AF.B.B1]| (AF.B.B1&0x0F? 0:H_FLAG);
   6.329 +   break;
   6.330 + case 0x3d:
   6.331 +   // DEC A
   6.332 +   AF.B.B1--;
   6.333 +   AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[AF.B.B1]|
   6.334 +     ((AF.B.B1&0x0F)==0x0F? H_FLAG:0);
   6.335 +   break;
   6.336 + case 0x3e:
   6.337 +   // LD A,NN
   6.338 +   AF.B.B1=gbReadOpcode(PC.W++);
   6.339 +   break;
   6.340 + case 0x3f:
   6.341 +   // CCF
   6.342 +   AF.B.B0^=C_FLAG;AF.B.B0&=~(N_FLAG|H_FLAG);
   6.343 +   break;
   6.344 + case 0x40:
   6.345 +   // LD B,B
   6.346 +   BC.B.B1=BC.B.B1;
   6.347 +   break;
   6.348 + case 0x41:
   6.349 +   // LD B,C
   6.350 +   BC.B.B1=BC.B.B0;
   6.351 +   break;
   6.352 + case 0x42:
   6.353 +   // LD B,D
   6.354 +   BC.B.B1=DE.B.B1;
   6.355 +   break;
   6.356 + case 0x43:
   6.357 +   // LD B,E
   6.358 +   BC.B.B1=DE.B.B0;
   6.359 +   break;
   6.360 + case 0x44:
   6.361 +   // LD B,H
   6.362 +   BC.B.B1=HL.B.B1;
   6.363 +   break;
   6.364 + case 0x45:
   6.365 +   // LD B,L
   6.366 +   BC.B.B1=HL.B.B0;
   6.367 +   break;
   6.368 + case 0x46:
   6.369 +   // LD B,(HL)
   6.370 +   BC.B.B1=gbReadMemory(HL.W);
   6.371 +   break;
   6.372 + case 0x47:
   6.373 +   // LD B,A
   6.374 +   BC.B.B1=AF.B.B1;
   6.375 +   break;
   6.376 + case 0x48:
   6.377 +   // LD C,B
   6.378 +   BC.B.B0=BC.B.B1;
   6.379 +   break;
   6.380 + case 0x49:
   6.381 +   // LD C,C
   6.382 +   BC.B.B0=BC.B.B0;
   6.383 +   break;
   6.384 + case 0x4a:
   6.385 +   // LD C,D
   6.386 +   BC.B.B0=DE.B.B1;
   6.387 +   break;
   6.388 + case 0x4b:
   6.389 +   // LD C,E
   6.390 +   BC.B.B0=DE.B.B0;
   6.391 +   break;
   6.392 + case 0x4c:
   6.393 +   // LD C,H
   6.394 +   BC.B.B0=HL.B.B1;
   6.395 +   break;
   6.396 + case 0x4d:
   6.397 +   // LD C,L
   6.398 +   BC.B.B0=HL.B.B0;
   6.399 +   break;
   6.400 + case 0x4e:
   6.401 +   // LD C,(HL)
   6.402 +   BC.B.B0=gbReadMemory(HL.W);
   6.403 +   break;
   6.404 + case 0x4f:
   6.405 +   // LD C,A
   6.406 +   BC.B.B0=AF.B.B1;
   6.407 +   break;
   6.408 + case 0x50:
   6.409 +   // LD D,B
   6.410 +   DE.B.B1=BC.B.B1;
   6.411 +   break;
   6.412 + case 0x51:
   6.413 +   // LD D,C
   6.414 +   DE.B.B1=BC.B.B0;
   6.415 +   break;
   6.416 + case 0x52:
   6.417 +   // LD D,D
   6.418 +   DE.B.B1=DE.B.B1;
   6.419 +   break;
   6.420 + case 0x53:
   6.421 +   // LD D,E
   6.422 +   DE.B.B1=DE.B.B0;
   6.423 +   break;
   6.424 + case 0x54:
   6.425 +   // LD D,H
   6.426 +   DE.B.B1=HL.B.B1;
   6.427 +   break;
   6.428 + case 0x55:
   6.429 +   // LD D,L
   6.430 +   DE.B.B1=HL.B.B0;
   6.431 +   break;
   6.432 + case 0x56:
   6.433 +   // LD D,(HL)
   6.434 +   DE.B.B1=gbReadMemory(HL.W);
   6.435 +   break;
   6.436 + case 0x57:
   6.437 +   // LD D,A
   6.438 +   DE.B.B1=AF.B.B1;
   6.439 +   break;
   6.440 + case 0x58:
   6.441 +   // LD E,B
   6.442 +   DE.B.B0=BC.B.B1;
   6.443 +   break;
   6.444 + case 0x59:
   6.445 +   // LD E,C
   6.446 +   DE.B.B0=BC.B.B0;
   6.447 +   break;
   6.448 + case 0x5a:
   6.449 +   // LD E,D
   6.450 +   DE.B.B0=DE.B.B1;
   6.451 +   break;
   6.452 + case 0x5b:
   6.453 +   // LD E,E
   6.454 +   DE.B.B0=DE.B.B0;
   6.455 +   break;
   6.456 + case 0x5c:
   6.457 +   // LD E,H
   6.458 +   DE.B.B0=HL.B.B1;
   6.459 +   break;
   6.460 + case 0x5d:
   6.461 +   // LD E,L
   6.462 +   DE.B.B0=HL.B.B0;
   6.463 +   break;
   6.464 + case 0x5e:
   6.465 +   // LD E,(HL)
   6.466 +   DE.B.B0=gbReadMemory(HL.W);
   6.467 +   break;
   6.468 + case 0x5f:
   6.469 +   // LD E,A
   6.470 +   DE.B.B0=AF.B.B1;
   6.471 +   break;
   6.472 + case 0x60:
   6.473 +   // LD H,B
   6.474 +   HL.B.B1=BC.B.B1;
   6.475 +   break;
   6.476 + case 0x61:
   6.477 +   // LD H,C
   6.478 +   HL.B.B1=BC.B.B0;
   6.479 +   break;
   6.480 + case 0x62:
   6.481 +   // LD H,D
   6.482 +   HL.B.B1=DE.B.B1;
   6.483 +   break;
   6.484 + case 0x63:
   6.485 +   // LD H,E
   6.486 +   HL.B.B1=DE.B.B0;
   6.487 +   break;
   6.488 + case 0x64:
   6.489 +   // LD H,H
   6.490 +   HL.B.B1=HL.B.B1;
   6.491 +   break;
   6.492 + case 0x65:
   6.493 +   // LD H,L
   6.494 +   HL.B.B1=HL.B.B0;
   6.495 +   break;
   6.496 + case 0x66:
   6.497 +   // LD H,(HL)
   6.498 +   HL.B.B1=gbReadMemory(HL.W);
   6.499 +   break;
   6.500 + case 0x67:
   6.501 +   // LD H,A
   6.502 +   HL.B.B1=AF.B.B1;
   6.503 +   break;
   6.504 + case 0x68:
   6.505 +   // LD L,B
   6.506 +   HL.B.B0=BC.B.B1;
   6.507 +   break;
   6.508 + case 0x69:
   6.509 +   // LD L,C
   6.510 +   HL.B.B0=BC.B.B0;
   6.511 +   break;
   6.512 + case 0x6a:
   6.513 +   // LD L,D
   6.514 +   HL.B.B0=DE.B.B1;
   6.515 +   break;
   6.516 + case 0x6b:
   6.517 +   // LD L,E
   6.518 +   HL.B.B0=DE.B.B0;
   6.519 +   break;
   6.520 + case 0x6c:
   6.521 +   // LD L,H
   6.522 +   HL.B.B0=HL.B.B1;
   6.523 +   break;
   6.524 + case 0x6d:
   6.525 +   // LD L,L
   6.526 +   HL.B.B0=HL.B.B0;
   6.527 +   break;
   6.528 + case 0x6e:
   6.529 +   // LD L,(HL)
   6.530 +   HL.B.B0=gbReadMemory(HL.W);
   6.531 +   break;
   6.532 + case 0x6f:
   6.533 +   // LD L,A
   6.534 +   HL.B.B0=AF.B.B1;
   6.535 +   break;
   6.536 + case 0x70:
   6.537 +   // LD (HL),B
   6.538 +   gbWriteMemory(HL.W,BC.B.B1);
   6.539 +   break;
   6.540 + case 0x71:
   6.541 +   // LD (HL),C
   6.542 +   gbWriteMemory(HL.W,BC.B.B0);
   6.543 +   break;
   6.544 + case 0x72:
   6.545 +   // LD (HL),D
   6.546 +   gbWriteMemory(HL.W,DE.B.B1);
   6.547 +   break;
   6.548 + case 0x73:
   6.549 +   // LD (HL),E
   6.550 +   gbWriteMemory(HL.W,DE.B.B0);
   6.551 +   break;
   6.552 + case 0x74:
   6.553 +   // LD (HL),H
   6.554 +   gbWriteMemory(HL.W,HL.B.B1);
   6.555 +   break;
   6.556 + case 0x75:
   6.557 +   // LD (HL),L
   6.558 +   gbWriteMemory(HL.W,HL.B.B0);
   6.559 +   break;
   6.560 + case 0x76:
   6.561 +   // HALT
   6.562 +   if(IFF & 1) {
   6.563 +     PC.W--;
   6.564 +     IFF |= 0x80;
   6.565 +   } else {
   6.566 +     if((register_IE & register_IF) > 0)
   6.567 +       IFF |= 0x100;
   6.568 +     else {
   6.569 +       PC.W--;
   6.570 +       IFF |= 0x81;
   6.571 +     }
   6.572 +   }
   6.573 +   break;
   6.574 + case 0x77:
   6.575 +   // LD (HL),A
   6.576 +   gbWriteMemory(HL.W,AF.B.B1);
   6.577 +   break;
   6.578 + case 0x78:
   6.579 +   // LD A,B
   6.580 +   AF.B.B1=BC.B.B1;
   6.581 +   break;
   6.582 + case 0x79:
   6.583 +   // LD A,C
   6.584 +   AF.B.B1=BC.B.B0;
   6.585 +   break;
   6.586 + case 0x7a:
   6.587 +   // LD A,D
   6.588 +   AF.B.B1=DE.B.B1;
   6.589 +   break;
   6.590 + case 0x7b:
   6.591 +   // LD A,E
   6.592 +   AF.B.B1=DE.B.B0;
   6.593 +   break;
   6.594 + case 0x7c:
   6.595 +   // LD A,H
   6.596 +   AF.B.B1=HL.B.B1;
   6.597 +   break;
   6.598 + case 0x7d:
   6.599 +   // LD A,L
   6.600 +   AF.B.B1=HL.B.B0;
   6.601 +   break;
   6.602 + case 0x7e:
   6.603 +   // LD A,(HL)
   6.604 +   AF.B.B1=gbReadMemory(HL.W);
   6.605 +   break;
   6.606 + case 0x7f:
   6.607 +   // LD A,A
   6.608 +   AF.B.B1=AF.B.B1;
   6.609 +   break;
   6.610 + case 0x80:
   6.611 +   // ADD B
   6.612 +   tempRegister.W=AF.B.B1+BC.B.B1;
   6.613 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.614 +     ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0);
   6.615 +   AF.B.B1=tempRegister.B.B0;
   6.616 +   break;
   6.617 + case 0x81:
   6.618 +   // ADD C
   6.619 +   tempRegister.W=AF.B.B1+BC.B.B0;
   6.620 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.621 +     ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0);
   6.622 +   AF.B.B1=tempRegister.B.B0;
   6.623 +   break;
   6.624 + case 0x82:
   6.625 +   // ADD D
   6.626 +   tempRegister.W=AF.B.B1+DE.B.B1;
   6.627 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.628 +     ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0);
   6.629 +   AF.B.B1=tempRegister.B.B0;
   6.630 +   break;
   6.631 + case 0x83:
   6.632 +   // ADD E
   6.633 +   tempRegister.W=AF.B.B1+DE.B.B0;
   6.634 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.635 +     ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0);
   6.636 +   AF.B.B1=tempRegister.B.B0;
   6.637 +   break;
   6.638 + case 0x84:
   6.639 +   // ADD H
   6.640 +   tempRegister.W=AF.B.B1+HL.B.B1;
   6.641 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.642 +     ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0);
   6.643 +   AF.B.B1=tempRegister.B.B0;
   6.644 +   break;
   6.645 + case 0x85:
   6.646 +   // ADD L
   6.647 +   tempRegister.W=AF.B.B1+HL.B.B0;
   6.648 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.649 +     ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0);
   6.650 +   AF.B.B1=tempRegister.B.B0;
   6.651 +   break;
   6.652 + case 0x86:
   6.653 +   // ADD (HL)
   6.654 +   tempValue=gbReadMemory(HL.W);
   6.655 +   tempRegister.W=AF.B.B1+tempValue;
   6.656 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.657 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10 ? H_FLAG:0);
   6.658 +   AF.B.B1=tempRegister.B.B0;
   6.659 +   break;
   6.660 + case 0x87:
   6.661 +   // ADD A
   6.662 +   tempRegister.W=AF.B.B1+AF.B.B1;
   6.663 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.664 +     ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0);
   6.665 +   AF.B.B1=tempRegister.B.B0;
   6.666 +   break;
   6.667 + case 0x88:
   6.668 +   // ADC B:
   6.669 +   tempRegister.W=AF.B.B1+BC.B.B1+(AF.B.B0&C_FLAG ? 1 : 0);
   6.670 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.671 +     ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.672 +   AF.B.B1=tempRegister.B.B0;
   6.673 +   break;
   6.674 + case 0x89:
   6.675 +   // ADC C
   6.676 +   tempRegister.W=AF.B.B1+BC.B.B0+(AF.B.B0&C_FLAG ? 1 : 0);
   6.677 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.678 +     ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.679 +   AF.B.B1=tempRegister.B.B0;
   6.680 +   break;
   6.681 + case 0x8a:
   6.682 +   // ADC D
   6.683 +   tempRegister.W=AF.B.B1+DE.B.B1+(AF.B.B0&C_FLAG ? 1 : 0);
   6.684 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.685 +     ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.686 +   AF.B.B1=tempRegister.B.B0;
   6.687 +   break;
   6.688 + case 0x8b:
   6.689 +   // ADC E
   6.690 +   tempRegister.W=AF.B.B1+DE.B.B0+(AF.B.B0&C_FLAG ? 1 : 0);
   6.691 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.692 +     ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.693 +   AF.B.B1=tempRegister.B.B0;
   6.694 +   break;
   6.695 + case 0x8c:
   6.696 +   // ADC H
   6.697 +   tempRegister.W=AF.B.B1+HL.B.B1+(AF.B.B0&C_FLAG ? 1 : 0);
   6.698 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.699 +     ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); AF.B.B1=tempRegister.B.B0;
   6.700 +   break;
   6.701 + case 0x8d:
   6.702 +   // ADC L
   6.703 +   tempRegister.W=AF.B.B1+HL.B.B0+(AF.B.B0&C_FLAG ? 1 : 0);
   6.704 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.705 +     ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.706 +   AF.B.B1=tempRegister.B.B0;
   6.707 +   break;
   6.708 + case 0x8e:
   6.709 +   // ADC (HL)
   6.710 +   tempValue=gbReadMemory(HL.W);
   6.711 +   tempRegister.W=AF.B.B1+tempValue+(AF.B.B0&C_FLAG ? 1 : 0);
   6.712 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.713 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.714 +   AF.B.B1=tempRegister.B.B0;
   6.715 +   break;
   6.716 + case 0x8f:
   6.717 +   // ADC A
   6.718 +   tempRegister.W=AF.B.B1+AF.B.B1+(AF.B.B0&C_FLAG ? 1 : 0);
   6.719 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.720 +     ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.721 +   AF.B.B1=tempRegister.B.B0;
   6.722 +   break;
   6.723 + case 0x90:
   6.724 +   // SUB B
   6.725 +   tempRegister.W=AF.B.B1-BC.B.B1;
   6.726 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.727 +     ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.728 +   AF.B.B1=tempRegister.B.B0;
   6.729 +   break;
   6.730 + case 0x91:
   6.731 +   // SUB C
   6.732 +   tempRegister.W=AF.B.B1-BC.B.B0;
   6.733 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.734 +     ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.735 +   AF.B.B1=tempRegister.B.B0;
   6.736 +   break;
   6.737 + case 0x92:
   6.738 +   // SUB D
   6.739 +   tempRegister.W=AF.B.B1-DE.B.B1;
   6.740 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.741 +     ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.742 +   AF.B.B1=tempRegister.B.B0;
   6.743 +   break;
   6.744 + case 0x93:
   6.745 +   // SUB E
   6.746 +   tempRegister.W=AF.B.B1-DE.B.B0;
   6.747 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.748 +     ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.749 +   AF.B.B1=tempRegister.B.B0;
   6.750 +   break;
   6.751 + case 0x94:
   6.752 +   // SUB H
   6.753 +   tempRegister.W=AF.B.B1-HL.B.B1;
   6.754 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.755 +     ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.756 +   AF.B.B1=tempRegister.B.B0;
   6.757 +   break;
   6.758 + case 0x95:
   6.759 +   // SUB L
   6.760 +   tempRegister.W=AF.B.B1-HL.B.B0;
   6.761 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.762 +     ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.763 +   AF.B.B1=tempRegister.B.B0;
   6.764 +   break;
   6.765 + case 0x96:
   6.766 +   // SUB (HL)
   6.767 +   tempValue=gbReadMemory(HL.W);
   6.768 +   tempRegister.W=AF.B.B1-tempValue;
   6.769 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.770 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.771 +   AF.B.B1=tempRegister.B.B0;
   6.772 +   break;
   6.773 + case 0x97:
   6.774 +   // SUB A
   6.775 +   AF.B.B1=0;
   6.776 +   AF.B.B0=N_FLAG|Z_FLAG;
   6.777 +   break;
   6.778 + case 0x98:
   6.779 +   // SBC B
   6.780 +   tempRegister.W=AF.B.B1-BC.B.B1-(AF.B.B0&C_FLAG ? 1 : 0);
   6.781 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.782 +     ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.783 +   AF.B.B1=tempRegister.B.B0;
   6.784 +   break;
   6.785 + case 0x99:
   6.786 +   // SBC C
   6.787 +   tempRegister.W=AF.B.B1-BC.B.B0-(AF.B.B0&C_FLAG ? 1 : 0);
   6.788 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.789 +     ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.790 +   AF.B.B1=tempRegister.B.B0;
   6.791 +   break;
   6.792 + case 0x9a:
   6.793 +   // SBC D
   6.794 +   tempRegister.W=AF.B.B1-DE.B.B1-(AF.B.B0&C_FLAG ? 1 : 0);
   6.795 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.796 +     ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.797 +   AF.B.B1=tempRegister.B.B0;
   6.798 +   break;
   6.799 + case 0x9b:
   6.800 +   // SBC E
   6.801 +   tempRegister.W=AF.B.B1-DE.B.B0-(AF.B.B0&C_FLAG ? 1 : 0);
   6.802 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.803 +     ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.804 +   AF.B.B1=tempRegister.B.B0;
   6.805 +   break;
   6.806 + case 0x9c:
   6.807 +   // SBC H
   6.808 +   tempRegister.W=AF.B.B1-HL.B.B1-(AF.B.B0&C_FLAG ? 1 : 0);
   6.809 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.810 +     ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.811 +   AF.B.B1=tempRegister.B.B0;
   6.812 +   break;
   6.813 + case 0x9d:
   6.814 +   // SBC L
   6.815 +   tempRegister.W=AF.B.B1-HL.B.B0-(AF.B.B0&C_FLAG ? 1 : 0);
   6.816 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.817 +     ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.818 +   AF.B.B1=tempRegister.B.B0;
   6.819 +   break;
   6.820 + case 0x9e:
   6.821 +   // SBC (HL)
   6.822 +   tempValue=gbReadMemory(HL.W);
   6.823 +   tempRegister.W=AF.B.B1-tempValue-(AF.B.B0&C_FLAG ? 1 : 0);
   6.824 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.825 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.826 +   AF.B.B1=tempRegister.B.B0;
   6.827 +   break;
   6.828 + case 0x9f:
   6.829 +   // SBC A
   6.830 +   tempRegister.W=AF.B.B1-AF.B.B1-(AF.B.B0&C_FLAG ? 1 : 0);
   6.831 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.832 +     ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.833 +   AF.B.B1=tempRegister.B.B0;
   6.834 +   break;
   6.835 + case 0xa0:
   6.836 +   // AND B
   6.837 +   AF.B.B1&=BC.B.B1;
   6.838 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
   6.839 +   break;
   6.840 + case 0xa1:
   6.841 +   // AND C
   6.842 +   AF.B.B1&=BC.B.B0;
   6.843 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
   6.844 +   break;
   6.845 + case 0xa2:
   6.846 +   // AND_D
   6.847 +   AF.B.B1&=DE.B.B1;
   6.848 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
   6.849 +   break;
   6.850 + case 0xa3:
   6.851 +   // AND E
   6.852 +   AF.B.B1&=DE.B.B0;
   6.853 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
   6.854 +   break;
   6.855 + case 0xa4:
   6.856 +   // AND H
   6.857 +   AF.B.B1&=HL.B.B1;
   6.858 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
   6.859 +   break;
   6.860 + case 0xa5:
   6.861 +   // AND L
   6.862 +   AF.B.B1&=HL.B.B0;
   6.863 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
   6.864 +   break;
   6.865 + case 0xa6:
   6.866 +   // AND (HL)
   6.867 +   tempValue=gbReadMemory(HL.W);
   6.868 +   AF.B.B1&=tempValue;
   6.869 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
   6.870 +   break;
   6.871 + case 0xa7:
   6.872 +   // AND A
   6.873 +   AF.B.B1&=AF.B.B1;
   6.874 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
   6.875 +   break;
   6.876 + case 0xa8:
   6.877 +   // XOR B
   6.878 +   AF.B.B1^=BC.B.B1;
   6.879 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.880 +   break;
   6.881 + case 0xa9:
   6.882 +   // XOR C
   6.883 +   AF.B.B1^=BC.B.B0;
   6.884 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.885 +   break;
   6.886 + case 0xaa:
   6.887 +   // XOR D
   6.888 +   AF.B.B1^=DE.B.B1;
   6.889 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.890 +   break;
   6.891 + case 0xab:
   6.892 +   // XOR E
   6.893 +   AF.B.B1^=DE.B.B0;
   6.894 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.895 +   break;
   6.896 + case 0xac:
   6.897 +   // XOR H
   6.898 +   AF.B.B1^=HL.B.B1;
   6.899 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.900 +   break;
   6.901 + case 0xad:
   6.902 +   // XOR L
   6.903 +   AF.B.B1^=HL.B.B0;
   6.904 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.905 +   break;
   6.906 + case 0xae:
   6.907 +   // XOR (HL)
   6.908 +   tempValue=gbReadMemory(HL.W);
   6.909 +   AF.B.B1^=tempValue;
   6.910 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.911 +   break;
   6.912 + case 0xaf:
   6.913 +   // XOR A
   6.914 +   AF.B.B1=0;
   6.915 +   AF.B.B0=Z_FLAG;
   6.916 +   break;
   6.917 + case 0xb0:
   6.918 +   // OR B
   6.919 +   AF.B.B1|=BC.B.B1;
   6.920 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.921 +   break;
   6.922 + case 0xb1:
   6.923 +   // OR C
   6.924 +   AF.B.B1|=BC.B.B0;
   6.925 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.926 +   break;
   6.927 + case 0xb2:
   6.928 +   // OR D
   6.929 +   AF.B.B1|=DE.B.B1;
   6.930 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.931 +   break;
   6.932 + case 0xb3:
   6.933 +   // OR E
   6.934 +   AF.B.B1|=DE.B.B0;
   6.935 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.936 +   break;
   6.937 + case 0xb4:
   6.938 +   // OR H
   6.939 +   AF.B.B1|=HL.B.B1;
   6.940 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.941 +   break;
   6.942 + case 0xb5:
   6.943 +   // OR L
   6.944 +   AF.B.B1|=HL.B.B0;
   6.945 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.946 +   break;
   6.947 + case 0xb6:
   6.948 +   // OR (HL)
   6.949 +   tempValue=gbReadMemory(HL.W);
   6.950 +   AF.B.B1|=tempValue;
   6.951 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.952 +   break;
   6.953 + case 0xb7:
   6.954 +   // OR A
   6.955 +   AF.B.B1|=AF.B.B1;
   6.956 +   AF.B.B0=ZeroTable[AF.B.B1];
   6.957 +   break;
   6.958 + case 0xb8:
   6.959 +   // CP B:
   6.960 +   tempRegister.W=AF.B.B1-BC.B.B1;
   6.961 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.962 +     ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.963 +   break;
   6.964 + case 0xb9:
   6.965 +   // CP C
   6.966 +   tempRegister.W=AF.B.B1-BC.B.B0;
   6.967 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.968 +     ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.969 +   break;
   6.970 + case 0xba:
   6.971 +   // CP D
   6.972 +   tempRegister.W=AF.B.B1-DE.B.B1;
   6.973 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.974 +     ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.975 +   break;
   6.976 + case 0xbb:
   6.977 +   // CP E
   6.978 +   tempRegister.W=AF.B.B1-DE.B.B0;
   6.979 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.980 +     ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.981 +   break;
   6.982 + case 0xbc:
   6.983 +   // CP H
   6.984 +   tempRegister.W=AF.B.B1-HL.B.B1;
   6.985 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.986 +     ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.987 +   break;
   6.988 + case 0xbd:
   6.989 +   // CP L
   6.990 +   tempRegister.W=AF.B.B1-HL.B.B0;
   6.991 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.992 +     ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0);
   6.993 +   break;
   6.994 + case 0xbe:
   6.995 +   // CP (HL)
   6.996 +   tempValue=gbReadMemory(HL.W);
   6.997 +   tempRegister.W=AF.B.B1-tempValue;
   6.998 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
   6.999 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0);
  6.1000 +   break;
  6.1001 + case 0xbf:
  6.1002 +   // CP A
  6.1003 +   AF.B.B0=N_FLAG|Z_FLAG;
  6.1004 +   break;
  6.1005 + case 0xc0:
  6.1006 +   // RET NZ
  6.1007 +   if(!(AF.B.B0&Z_FLAG)) {
  6.1008 +     PC.B.B0=gbReadMemory(SP.W++);
  6.1009 +     PC.B.B1=gbReadMemory(SP.W++);
  6.1010 +     clockTicks += 3;
  6.1011 +   }
  6.1012 +   break;
  6.1013 + case 0xc1:
  6.1014 +   // POP BC
  6.1015 +   BC.B.B0=gbReadMemory(SP.W++);
  6.1016 +   BC.B.B1=gbReadMemory(SP.W++);
  6.1017 +   break;
  6.1018 + case 0xc2:
  6.1019 +   // JP NZ,NNNN
  6.1020 +   if(AF.B.B0&Z_FLAG)
  6.1021 +     PC.W+=2;
  6.1022 +   else {
  6.1023 +     tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1024 +     tempRegister.B.B1=gbReadMemory(PC.W);
  6.1025 +     PC.W=tempRegister.W;
  6.1026 +     clockTicks++;
  6.1027 +   }
  6.1028 +   break;
  6.1029 + case 0xc3:
  6.1030 +   // JP NNNN
  6.1031 +   tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1032 +   tempRegister.B.B1=gbReadMemory(PC.W);
  6.1033 +   PC.W=tempRegister.W;
  6.1034 +   break;
  6.1035 + case 0xc4:
  6.1036 +   // CALL NZ,NNNN
  6.1037 +   if(AF.B.B0&Z_FLAG)
  6.1038 +     PC.W+=2;
  6.1039 +   else {
  6.1040 +     tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1041 +     tempRegister.B.B1=gbReadMemory(PC.W++);
  6.1042 +     gbWriteMemory(--SP.W,PC.B.B1);
  6.1043 +     gbWriteMemory(--SP.W,PC.B.B0);
  6.1044 +     PC.W=tempRegister.W;
  6.1045 +     clockTicks += 3;
  6.1046 +   }
  6.1047 +   break;
  6.1048 + case 0xc5:
  6.1049 +   // PUSH BC
  6.1050 +   gbWriteMemory(--SP.W,BC.B.B1);
  6.1051 +   gbWriteMemory(--SP.W,BC.B.B0);
  6.1052 +   break;
  6.1053 + case 0xc6:
  6.1054 +   // ADD NN
  6.1055 +   tempValue=gbReadOpcode(PC.W++);
  6.1056 +   tempRegister.W=AF.B.B1+tempValue;
  6.1057 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
  6.1058 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10 ? H_FLAG:0);
  6.1059 +   AF.B.B1=tempRegister.B.B0;
  6.1060 +   break;
  6.1061 + case 0xc7:
  6.1062 +   // RST 00
  6.1063 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1064 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1065 +   PC.W=0x0000;
  6.1066 +   break;
  6.1067 + case 0xc8:
  6.1068 +   // RET Z
  6.1069 +   if(AF.B.B0&Z_FLAG) {
  6.1070 +     PC.B.B0=gbReadMemory(SP.W++);
  6.1071 +     PC.B.B1=gbReadMemory(SP.W++);
  6.1072 +     clockTicks += 3;
  6.1073 +   }
  6.1074 +   break;
  6.1075 + case 0xc9:
  6.1076 +   // RET
  6.1077 +   PC.B.B0=gbReadMemory(SP.W++);
  6.1078 +   PC.B.B1=gbReadMemory(SP.W++);
  6.1079 +   break;
  6.1080 + case 0xca:
  6.1081 +   // JP Z,NNNN
  6.1082 +   if(AF.B.B0&Z_FLAG) {
  6.1083 +     tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1084 +     tempRegister.B.B1=gbReadMemory(PC.W);
  6.1085 +     PC.W=tempRegister.W;
  6.1086 +     clockTicks++;
  6.1087 +   } else
  6.1088 +     PC.W+=2;
  6.1089 +   break;
  6.1090 +   // CB done outside
  6.1091 + case 0xcc:
  6.1092 +   // CALL Z,NNNN
  6.1093 +   if(AF.B.B0&Z_FLAG) {
  6.1094 +     tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1095 +     tempRegister.B.B1=gbReadMemory(PC.W++);
  6.1096 +     gbWriteMemory(--SP.W,PC.B.B1);
  6.1097 +     gbWriteMemory(--SP.W,PC.B.B0);
  6.1098 +     PC.W=tempRegister.W;
  6.1099 +     clockTicks += 3;
  6.1100 +   } else
  6.1101 +     PC.W+=2;
  6.1102 +   break;
  6.1103 + case 0xcd:
  6.1104 +   // CALL NNNN
  6.1105 +   tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1106 +   tempRegister.B.B1=gbReadMemory(PC.W++);
  6.1107 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1108 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1109 +   PC.W=tempRegister.W;
  6.1110 +   break;
  6.1111 + case 0xce:
  6.1112 +   // ADC NN
  6.1113 +   tempValue=gbReadOpcode(PC.W++);
  6.1114 +   tempRegister.W=AF.B.B1+tempValue+(AF.B.B0&C_FLAG ? 1 : 0);
  6.1115 +   AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
  6.1116 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0);
  6.1117 +   AF.B.B1=tempRegister.B.B0;
  6.1118 +   break;
  6.1119 + case 0xcf:
  6.1120 +   // RST 08
  6.1121 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1122 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1123 +   PC.W=0x0008;
  6.1124 +   break;
  6.1125 + case 0xd0:
  6.1126 +   // RET NC
  6.1127 +   if(!(AF.B.B0&C_FLAG)) {
  6.1128 +     PC.B.B0=gbReadMemory(SP.W++);
  6.1129 +     PC.B.B1=gbReadMemory(SP.W++);
  6.1130 +     clockTicks += 3;
  6.1131 +   }
  6.1132 +   break;
  6.1133 + case 0xd1:
  6.1134 +   // POP DE
  6.1135 +   DE.B.B0=gbReadMemory(SP.W++);
  6.1136 +   DE.B.B1=gbReadMemory(SP.W++);
  6.1137 +   break;
  6.1138 + case 0xd2:
  6.1139 +   // JP NC,NNNN
  6.1140 +   if(AF.B.B0&C_FLAG)
  6.1141 +     PC.W+=2;
  6.1142 +   else {
  6.1143 +     tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1144 +     tempRegister.B.B1=gbReadMemory(PC.W);
  6.1145 +     PC.W=tempRegister.W;
  6.1146 +     clockTicks++;
  6.1147 +   }
  6.1148 +   break;
  6.1149 +   // D3 illegal
  6.1150 + case 0xd4:
  6.1151 +   // CALL NC,NNNN
  6.1152 +   if(AF.B.B0&C_FLAG)
  6.1153 +     PC.W+=2;
  6.1154 +   else {
  6.1155 +     tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1156 +     tempRegister.B.B1=gbReadMemory(PC.W++);
  6.1157 +     gbWriteMemory(--SP.W,PC.B.B1);
  6.1158 +     gbWriteMemory(--SP.W,PC.B.B0);
  6.1159 +     PC.W=tempRegister.W;
  6.1160 +     clockTicks += 3;
  6.1161 +   }
  6.1162 +   break;
  6.1163 + case 0xd5:
  6.1164 +   // PUSH DE
  6.1165 +   gbWriteMemory(--SP.W,DE.B.B1);
  6.1166 +   gbWriteMemory(--SP.W,DE.B.B0);
  6.1167 +   break;
  6.1168 + case 0xd6:
  6.1169 +   // SUB NN
  6.1170 +   tempValue=gbReadOpcode(PC.W++);
  6.1171 +   tempRegister.W=AF.B.B1-tempValue;
  6.1172 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
  6.1173 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0);
  6.1174 +   AF.B.B1=tempRegister.B.B0;
  6.1175 +   break;
  6.1176 + case 0xd7:
  6.1177 +   // RST 10
  6.1178 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1179 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1180 +   PC.W=0x0010;
  6.1181 +   break;
  6.1182 + case 0xd8:
  6.1183 +   // RET C
  6.1184 +   if(AF.B.B0&C_FLAG) {
  6.1185 +     PC.B.B0=gbReadMemory(SP.W++);
  6.1186 +     PC.B.B1=gbReadMemory(SP.W++);
  6.1187 +     clockTicks += 4;
  6.1188 +   }
  6.1189 +   break;
  6.1190 + case 0xd9:
  6.1191 +   // RETI
  6.1192 +   PC.B.B0=gbReadMemory(SP.W++);
  6.1193 +   PC.B.B1=gbReadMemory(SP.W++);
  6.1194 +   IFF |= 0x01;
  6.1195 +   break;
  6.1196 + case 0xda:
  6.1197 +   // JP C,NNNN
  6.1198 +   if(AF.B.B0&C_FLAG) {
  6.1199 +     tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1200 +     tempRegister.B.B1=gbReadMemory(PC.W);
  6.1201 +     PC.W=tempRegister.W;
  6.1202 +     clockTicks++;
  6.1203 +   } else
  6.1204 +     PC.W+=2;
  6.1205 +   break;
  6.1206 +   // DB illegal
  6.1207 + case 0xdc:
  6.1208 +   // CALL C,NNNN
  6.1209 +   if(AF.B.B0&C_FLAG) {
  6.1210 +     tempRegister.B.B0=gbReadMemory(PC.W++);
  6.1211 +     tempRegister.B.B1=gbReadMemory(PC.W++);
  6.1212 +     gbWriteMemory(--SP.W,PC.B.B1);
  6.1213 +     gbWriteMemory(--SP.W,PC.B.B0);
  6.1214 +     PC.W=tempRegister.W;
  6.1215 +     clockTicks += 3;
  6.1216 +   } else
  6.1217 +     PC.W+=2;
  6.1218 +   break;
  6.1219 +   // DD illegal
  6.1220 + case 0xde:
  6.1221 +   // SBC NN
  6.1222 +   tempValue=gbReadOpcode(PC.W++);
  6.1223 +   tempRegister.W=AF.B.B1-tempValue-(AF.B.B0&C_FLAG ? 1 : 0);
  6.1224 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
  6.1225 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0);
  6.1226 +   AF.B.B1=tempRegister.B.B0;
  6.1227 +   break;
  6.1228 + case 0xdf:
  6.1229 +   // RST 18
  6.1230 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1231 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1232 +   PC.W=0x0018;
  6.1233 +   break;
  6.1234 + case 0xe0:
  6.1235 +   // LD (FF00+NN),A
  6.1236 +   gbWriteMemory(0xff00 + gbReadOpcode(PC.W++),AF.B.B1);
  6.1237 +   break;
  6.1238 + case 0xe1:
  6.1239 +   // POP HL
  6.1240 +   HL.B.B0=gbReadMemory(SP.W++);
  6.1241 +   HL.B.B1=gbReadMemory(SP.W++);
  6.1242 +   break;
  6.1243 + case 0xe2:
  6.1244 +   // LD (FF00+C),A
  6.1245 +   gbWriteMemory(0xff00 + BC.B.B0,AF.B.B1);
  6.1246 +   break;
  6.1247 +   // E3 illegal
  6.1248 +   // E4 illegal
  6.1249 + case 0xe5:
  6.1250 +   // PUSH HL
  6.1251 +   gbWriteMemory(--SP.W,HL.B.B1);
  6.1252 +   gbWriteMemory(--SP.W,HL.B.B0);
  6.1253 +   break;
  6.1254 + case 0xe6:
  6.1255 +   // AND NN
  6.1256 +   tempValue=gbReadOpcode(PC.W++);
  6.1257 +   AF.B.B1&=tempValue;
  6.1258 +   AF.B.B0=H_FLAG|ZeroTable[AF.B.B1];
  6.1259 +   break;
  6.1260 + case 0xe7:
  6.1261 +   // RST 20
  6.1262 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1263 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1264 +   PC.W=0x0020;
  6.1265 +   break;
  6.1266 + case 0xe8:
  6.1267 +   // ADD SP,NN
  6.1268 +   offset = (s8)gbReadOpcode(PC.W++);
  6.1269 +   
  6.1270 +   if(offset >= 0) {
  6.1271 +     tempRegister.W = SP.W + offset;
  6.1272 +     AF.B.B0 = (SP.W > tempRegister.W ? C_FLAG : 0) |
  6.1273 +       ((SP.W^offset^tempRegister.W)&0x1000? H_FLAG:0);
  6.1274 +     SP.W = tempRegister.W;
  6.1275 +   } else {
  6.1276 +     tempRegister.W = SP.W + offset;
  6.1277 +     AF.B.B0 = (SP.W < tempRegister.W ? C_FLAG : 0) |
  6.1278 +       ((SP.W^offset^tempRegister.W)&0x1000?H_FLAG:0);
  6.1279 +     SP.W = tempRegister.W;
  6.1280 +   }
  6.1281 +   break;
  6.1282 + case 0xe9:
  6.1283 +   // LD PC,HL
  6.1284 +   PC.W=HL.W;
  6.1285 +   break;
  6.1286 + case 0xea:
  6.1287 +   // LD (NNNN),A
  6.1288 +   tempRegister.B.B0=gbReadOpcode(PC.W++);
  6.1289 +   tempRegister.B.B1=gbReadOpcode(PC.W++);
  6.1290 +   gbWriteMemory(tempRegister.W,AF.B.B1);
  6.1291 +   break;
  6.1292 +   // EB illegal
  6.1293 +   // EC illegal
  6.1294 +   // ED illegal
  6.1295 + case 0xee:
  6.1296 +   // XOR NN
  6.1297 +   tempValue=gbReadOpcode(PC.W++);
  6.1298 +   AF.B.B1^=tempValue;
  6.1299 +   AF.B.B0=ZeroTable[AF.B.B1];
  6.1300 +   break;
  6.1301 + case 0xef:
  6.1302 +   // RST 28
  6.1303 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1304 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1305 +   PC.W=0x0028;
  6.1306 +   break;
  6.1307 + case 0xf0:
  6.1308 +   // LD A,(FF00+NN)
  6.1309 +   AF.B.B1 = gbReadMemory(0xff00+gbReadOpcode(PC.W++));
  6.1310 +   break;
  6.1311 + case 0xf1:
  6.1312 +   // POP AF
  6.1313 +   AF.B.B0=gbReadMemory(SP.W++);
  6.1314 +   AF.B.B1=gbReadMemory(SP.W++);
  6.1315 +   break;
  6.1316 + case 0xf2:
  6.1317 +   // LD A,(FF00+C)
  6.1318 +   AF.B.B1 = gbReadMemory(0xff00+BC.B.B0);
  6.1319 +   break;
  6.1320 + case 0xf3:
  6.1321 +   // DI
  6.1322 + //   IFF&=0xFE;
  6.1323 +   IFF&=(~0x21);
  6.1324 +   break;
  6.1325 +   // F4 illegal
  6.1326 + case 0xf5:
  6.1327 +   // PUSH AF
  6.1328 +   gbWriteMemory(--SP.W,AF.B.B1);
  6.1329 +   gbWriteMemory(--SP.W,AF.B.B0);
  6.1330 +   break;
  6.1331 + case 0xf6:
  6.1332 +   // OR NN
  6.1333 +   tempValue=gbReadOpcode(PC.W++);
  6.1334 +   AF.B.B1|=tempValue;
  6.1335 +   AF.B.B0=ZeroTable[AF.B.B1];
  6.1336 +   break;
  6.1337 + case 0xf7:
  6.1338 +   // RST 30
  6.1339 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1340 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1341 +   PC.W=0x0030;
  6.1342 +   break;
  6.1343 + case 0xf8:
  6.1344 +   // LD HL,SP+NN
  6.1345 +   offset = (s8)gbReadOpcode(PC.W++);
  6.1346 +   if(offset >= 0) {
  6.1347 +     tempRegister.W = SP.W + offset;
  6.1348 +     AF.B.B0 = (SP.W > tempRegister.W ? C_FLAG : 0) |
  6.1349 +       ((SP.W^offset^tempRegister.W)&0x1000? H_FLAG:0);
  6.1350 +     HL.W = tempRegister.W;
  6.1351 +   } else {
  6.1352 +     tempRegister.W = SP.W + offset;
  6.1353 +     AF.B.B0 = (SP.W < tempRegister.W ? C_FLAG : 0) |
  6.1354 +       ((SP.W^offset^tempRegister.W)&0x1000?H_FLAG:0);
  6.1355 +     HL.W = tempRegister.W;
  6.1356 +   }
  6.1357 +   break;
  6.1358 + case 0xf9:
  6.1359 +   // LD SP,HL
  6.1360 +   SP.W=HL.W;
  6.1361 +   break;
  6.1362 + case 0xfa:
  6.1363 +   // LD A,(NNNN)
  6.1364 +   tempRegister.B.B0=gbReadOpcode(PC.W++);
  6.1365 +   tempRegister.B.B1=gbReadOpcode(PC.W++);
  6.1366 +   AF.B.B1=gbReadMemory(tempRegister.W);
  6.1367 +   break;
  6.1368 + case 0xfb:
  6.1369 +   // EI
  6.1370 +   IFF|=0x20;
  6.1371 +   break;
  6.1372 +   // FC illegal
  6.1373 +   // FD illegal
  6.1374 + case 0xfe:
  6.1375 +   // CP NN
  6.1376 +   tempValue=gbReadOpcode(PC.W++);
  6.1377 +   tempRegister.W=AF.B.B1-tempValue;
  6.1378 +   AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]|
  6.1379 +     ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0);
  6.1380 +   break;
  6.1381 + case 0xff:
  6.1382 +   // RST 38
  6.1383 +   gbWriteMemory(--SP.W,PC.B.B1);
  6.1384 +   gbWriteMemory(--SP.W,PC.B.B0);
  6.1385 +   PC.W=0x0038;
  6.1386 +   break;
  6.1387 + default:
  6.1388 +   systemMessage(0, N_("Unknown opcode %02x at %04x"),
  6.1389 +                 gbReadOpcode(PC.W-1),PC.W-1);
  6.1390 +   emulating = false;
  6.1391 +   return;
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/gb/gbCodesCB.h	Sat Mar 03 11:44:47 2012 -0600
     7.3 @@ -0,0 +1,1269 @@
     7.4 + case 0x00:
     7.5 +   // RLC B
     7.6 +   AF.B.B0 = (BC.B.B1 & 0x80)?C_FLAG:0;
     7.7 +   BC.B.B1 = ((BC.B.B1<<1) | (BC.B.B1>>7)) & 0xFF;
     7.8 +   AF.B.B0 |= ZeroTable[BC.B.B1];
     7.9 +   break;
    7.10 + case 0x01:
    7.11 +   // RLC C
    7.12 +   AF.B.B0 = (BC.B.B0 & 0x80)?C_FLAG:0;
    7.13 +   BC.B.B0 = ((BC.B.B0<<1) | (BC.B.B0>>7)) & 0xFF;
    7.14 +   AF.B.B0 |= ZeroTable[BC.B.B0];
    7.15 +   break;
    7.16 + case 0x02:
    7.17 +   // RLC D
    7.18 +   AF.B.B0 = (DE.B.B1 & 0x80)?C_FLAG:0;
    7.19 +   DE.B.B1 = ((DE.B.B1<<1) | (DE.B.B1>>7)) & 0xFF;
    7.20 +   AF.B.B0 |= ZeroTable[DE.B.B1];
    7.21 +   break;
    7.22 + case 0x03:
    7.23 +   // RLC E
    7.24 +   AF.B.B0 = (DE.B.B0 & 0x80)?C_FLAG:0;
    7.25 +   DE.B.B0 = ((DE.B.B0<<1) | (DE.B.B0>>7)) & 0xFF;
    7.26 +   AF.B.B0 |= ZeroTable[DE.B.B0];
    7.27 +   break;
    7.28 + case 0x04:
    7.29 +   // RLC H
    7.30 +   AF.B.B0 = (HL.B.B1 & 0x80)?C_FLAG:0;
    7.31 +   HL.B.B1 = ((HL.B.B1<<1) | (HL.B.B1>>7)) & 0xFF;
    7.32 +   AF.B.B0 |= ZeroTable[HL.B.B1];
    7.33 +   break;
    7.34 + case 0x05:
    7.35 +   // RLC L
    7.36 +   AF.B.B0 = (HL.B.B0 & 0x80)?C_FLAG:0;
    7.37 +   HL.B.B0 = ((HL.B.B0<<1) | (HL.B.B0>>7)) & 0xFF;
    7.38 +   AF.B.B0 |= ZeroTable[HL.B.B0];
    7.39 +   break;
    7.40 + case 0x06:
    7.41 +   // RLC (HL)
    7.42 +   tempValue=gbReadMemory(HL.W);
    7.43 +   AF.B.B0 = (tempValue & 0x80)?C_FLAG:0;
    7.44 +   tempValue = ((tempValue<<1) | (tempValue>>7)) & 0xFF;
    7.45 +   AF.B.B0 |= ZeroTable[tempValue];
    7.46 +   gbWriteMemory(HL.W,tempValue);
    7.47 +   break;
    7.48 + case 0x07:
    7.49 +   // RLC A
    7.50 +   AF.B.B0 = (AF.B.B1 & 0x80)?C_FLAG:0;
    7.51 +   AF.B.B1 = ((AF.B.B1<<1) | (AF.B.B1>>7)) & 0xFF;
    7.52 +   AF.B.B0 |= ZeroTable[AF.B.B1];
    7.53 +   break;
    7.54 + case 0x08:
    7.55 +   // RRC B
    7.56 +   AF.B.B0=(BC.B.B1&0x01 ? C_FLAG : 0);
    7.57 +   BC.B.B1=((BC.B.B1>>1)|(BC.B.B1<<7)) & 0xFF;
    7.58 +   AF.B.B0|=ZeroTable[BC.B.B1];
    7.59 +   break;
    7.60 + case 0x09:
    7.61 +   // RRC C
    7.62 +   AF.B.B0=(BC.B.B0&0x01 ? C_FLAG : 0);
    7.63 +   BC.B.B0=((BC.B.B0>>1)|(BC.B.B0<<7)) & 0xFF;
    7.64 +   AF.B.B0|=ZeroTable[BC.B.B0];
    7.65 +   break;
    7.66 + case 0x0a:
    7.67 +   // RRC D
    7.68 +   AF.B.B0=(DE.B.B1&0x01 ? C_FLAG : 0);
    7.69 +   DE.B.B1=((DE.B.B1>>1)|(DE.B.B1<<7)) & 0xFF;
    7.70 +   AF.B.B0|=ZeroTable[DE.B.B1];
    7.71 +   break;
    7.72 + case 0x0b:
    7.73 +   // RRC E
    7.74 +   AF.B.B0=(DE.B.B0&0x01 ? C_FLAG : 0);
    7.75 +   DE.B.B0=((DE.B.B0>>1)|(DE.B.B0<<7)) & 0xFF;
    7.76 +   AF.B.B0|=ZeroTable[DE.B.B0];
    7.77 +   break;
    7.78 + case 0x0c:
    7.79 +   // RRC H
    7.80 +   AF.B.B0=(HL.B.B1&0x01 ? C_FLAG : 0);
    7.81 +   HL.B.B1=((HL.B.B1>>1)|(HL.B.B1<<7)) & 0xFF;
    7.82 +   AF.B.B0|=ZeroTable[HL.B.B1];
    7.83 +   break;
    7.84 + case 0x0d:
    7.85 +   // RRC L
    7.86 +   AF.B.B0=(HL.B.B0&0x01 ? C_FLAG : 0);
    7.87 +   HL.B.B0=((HL.B.B0>>1)|(HL.B.B0<<7)) & 0xFF;
    7.88 +   AF.B.B0|=ZeroTable[HL.B.B0];
    7.89 +   break;
    7.90 + case 0x0e:
    7.91 +   // RRC (HL)
    7.92 +   tempValue=gbReadMemory(HL.W);
    7.93 +   AF.B.B0=(tempValue&0x01 ? C_FLAG : 0);
    7.94 +   tempValue=((tempValue>>1)|(tempValue<<7)) & 0xFF;
    7.95 +   AF.B.B0|=ZeroTable[tempValue];
    7.96 +   gbWriteMemory(HL.W,tempValue);
    7.97 +   break;
    7.98 + case 0x0f:
    7.99 +   // RRC A
   7.100 +   AF.B.B0=(AF.B.B1&0x01 ? C_FLAG : 0);
   7.101 +   AF.B.B1=((AF.B.B1>>1)|(AF.B.B1<<7)) & 0xFF;
   7.102 +   AF.B.B0|=ZeroTable[AF.B.B1];
   7.103 +   break;
   7.104 + case 0x10:
   7.105 +   // RL B
   7.106 +   if(BC.B.B1&0x80) {
   7.107 +     BC.B.B1=((BC.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.108 +     AF.B.B0=ZeroTable[BC.B.B1]|C_FLAG;
   7.109 +   } else {
   7.110 +     BC.B.B1=((BC.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.111 +     AF.B.B0=ZeroTable[BC.B.B1];
   7.112 +   }
   7.113 +   break;
   7.114 + case 0x11:
   7.115 +   // RL C
   7.116 +   if(BC.B.B0&0x80) {
   7.117 +     BC.B.B0=((BC.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.118 +     AF.B.B0=ZeroTable[BC.B.B0]|C_FLAG;
   7.119 +   } else {
   7.120 +     BC.B.B0=((BC.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.121 +     AF.B.B0=ZeroTable[BC.B.B0];
   7.122 +   }
   7.123 +   break;
   7.124 + case 0x12:
   7.125 +   // RL D
   7.126 +   if(DE.B.B1&0x80) {
   7.127 +     DE.B.B1=((DE.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.128 +     AF.B.B0=ZeroTable[DE.B.B1]|C_FLAG;
   7.129 +   } else {
   7.130 +     DE.B.B1=((DE.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.131 +     AF.B.B0=ZeroTable[DE.B.B1];
   7.132 +   }
   7.133 +   break;
   7.134 + case 0x13:
   7.135 +   // RL E
   7.136 +   if(DE.B.B0&0x80) {
   7.137 +     DE.B.B0=((DE.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.138 +     AF.B.B0=ZeroTable[DE.B.B0]|C_FLAG;
   7.139 +   } else {
   7.140 +     DE.B.B0=((DE.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.141 +     AF.B.B0=ZeroTable[DE.B.B0];
   7.142 +   }
   7.143 +   break;
   7.144 + case 0x14:
   7.145 +   // RL H
   7.146 +   if(HL.B.B1&0x80) {
   7.147 +     HL.B.B1=((HL.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.148 +     AF.B.B0=ZeroTable[HL.B.B1]|C_FLAG;
   7.149 +   } else {
   7.150 +     HL.B.B1=((HL.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.151 +     AF.B.B0=ZeroTable[HL.B.B1];
   7.152 +   }
   7.153 +   break;
   7.154 + case 0x15:
   7.155 +   // RL L
   7.156 +   if(HL.B.B0&0x80) {
   7.157 +     HL.B.B0=((HL.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.158 +     AF.B.B0=ZeroTable[HL.B.B0]|C_FLAG;
   7.159 +   } else {
   7.160 +     HL.B.B0=((HL.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.161 +     AF.B.B0=ZeroTable[HL.B.B0];
   7.162 +   }
   7.163 +   break;
   7.164 + case 0x16:
   7.165 +   // RL (HL)
   7.166 +   tempValue=gbReadMemory(HL.W);
   7.167 +   if(tempValue&0x80) {
   7.168 +     tempValue=((tempValue<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.169 +     AF.B.B0=ZeroTable[tempValue]|C_FLAG;
   7.170 +   } else {
   7.171 +     tempValue=((tempValue<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.172 +     AF.B.B0=ZeroTable[tempValue];
   7.173 +   }
   7.174 +   gbWriteMemory(HL.W,tempValue);
   7.175 +   break;
   7.176 + case 0x17:
   7.177 +   // RL A
   7.178 +   if(AF.B.B1&0x80) {
   7.179 +     AF.B.B1=((AF.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.180 +     AF.B.B0=ZeroTable[AF.B.B1]|C_FLAG;
   7.181 +   } else {
   7.182 +     AF.B.B1=((AF.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF;
   7.183 +     AF.B.B0=ZeroTable[AF.B.B1];
   7.184 +   }
   7.185 +   break;
   7.186 + case 0x18:
   7.187 +   // RR B
   7.188 +   if(BC.B.B1&0x01) {
   7.189 +     BC.B.B1=(BC.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.190 +     AF.B.B0=ZeroTable[BC.B.B1]|C_FLAG;
   7.191 +   } else {
   7.192 +     BC.B.B1=(BC.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.193 +     AF.B.B0=ZeroTable[BC.B.B1];
   7.194 +   }
   7.195 +   break;
   7.196 + case 0x19:
   7.197 +   // RR C
   7.198 +   if(BC.B.B0&0x01) {
   7.199 +     BC.B.B0=(BC.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.200 +     AF.B.B0=ZeroTable[BC.B.B0]|C_FLAG;
   7.201 +   } else {
   7.202 +     BC.B.B0=(BC.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.203 +     AF.B.B0=ZeroTable[BC.B.B0];
   7.204 +   }
   7.205 +   break;
   7.206 + case 0x1a:
   7.207 +   // RR D
   7.208 +   if(DE.B.B1&0x01) {
   7.209 +     DE.B.B1=(DE.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.210 +     AF.B.B0=ZeroTable[DE.B.B1]|C_FLAG;
   7.211 +   } else {
   7.212 +     DE.B.B1=(DE.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.213 +     AF.B.B0=ZeroTable[DE.B.B1];
   7.214 +   }
   7.215 +   break;
   7.216 + case 0x1b:
   7.217 +   // RR E
   7.218 +   if(DE.B.B0&0x01) {
   7.219 +     DE.B.B0=(DE.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.220 +     AF.B.B0=ZeroTable[DE.B.B0]|C_FLAG;
   7.221 +   } else {
   7.222 +     DE.B.B0=(DE.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.223 +     AF.B.B0=ZeroTable[DE.B.B0];
   7.224 +   }
   7.225 +   break;
   7.226 + case 0x1c:
   7.227 +   // RR H
   7.228 +   if(HL.B.B1&0x01) {
   7.229 +     HL.B.B1=(HL.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.230 +     AF.B.B0=ZeroTable[HL.B.B1]|C_FLAG;
   7.231 +   } else {
   7.232 +     HL.B.B1=(HL.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.233 +     AF.B.B0=ZeroTable[HL.B.B1];
   7.234 +   }
   7.235 +   break;
   7.236 + case 0x1d:
   7.237 +   // RR L
   7.238 +   if(HL.B.B0&0x01) {
   7.239 +     HL.B.B0=(HL.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.240 +     AF.B.B0=ZeroTable[HL.B.B0]|C_FLAG;
   7.241 +   } else {
   7.242 +     HL.B.B0=(HL.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.243 +     AF.B.B0=ZeroTable[HL.B.B0];
   7.244 +   }
   7.245 +   break;
   7.246 + case 0x1e:
   7.247 +   // RR (HL)
   7.248 +   tempValue=gbReadMemory(HL.W);
   7.249 +   if(tempValue&0x01) {
   7.250 +     tempValue=(tempValue>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.251 +     AF.B.B0=ZeroTable[tempValue]|C_FLAG;
   7.252 +   } else {
   7.253 +     tempValue=(tempValue>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.254 +     AF.B.B0=ZeroTable[tempValue];
   7.255 +   }
   7.256 +   gbWriteMemory(HL.W,tempValue);
   7.257 +   break;
   7.258 + case 0x1f:
   7.259 +   // RR A
   7.260 +   if(AF.B.B1&0x01) {
   7.261 +     AF.B.B1=(AF.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.262 +     AF.B.B0=ZeroTable[AF.B.B1]|C_FLAG;
   7.263 +   } else {
   7.264 +     AF.B.B1=(AF.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0);
   7.265 +     AF.B.B0=ZeroTable[AF.B.B1];
   7.266 +   }
   7.267 +   break;
   7.268 + case 0x20:
   7.269 +   // SLA B
   7.270 +   AF.B.B0=(BC.B.B1&0x80?C_FLAG : 0);
   7.271 +   BC.B.B1<<=1;
   7.272 +   AF.B.B0|=ZeroTable[BC.B.B1];
   7.273 +   break;
   7.274 + case 0x21:
   7.275 +   // SLA C
   7.276 +   AF.B.B0=(BC.B.B0&0x80?C_FLAG : 0);
   7.277 +   BC.B.B0<<=1;
   7.278 +   AF.B.B0|=ZeroTable[BC.B.B0];
   7.279 +   break;
   7.280 + case 0x22:
   7.281 +   // SLA D
   7.282 +   AF.B.B0=(DE.B.B1&0x80?C_FLAG : 0);
   7.283 +   DE.B.B1<<=1;
   7.284 +   AF.B.B0|=ZeroTable[DE.B.B1];
   7.285 +   break;
   7.286 + case 0x23:
   7.287 +   // SLA E
   7.288 +   AF.B.B0=(DE.B.B0&0x80?C_FLAG : 0);
   7.289 +   DE.B.B0<<=1;
   7.290 +   AF.B.B0|=ZeroTable[DE.B.B0];
   7.291 +   break;
   7.292 + case 0x24:
   7.293 +   // SLA H
   7.294 +   AF.B.B0=(HL.B.B1&0x80?C_FLAG : 0);
   7.295 +   HL.B.B1<<=1;
   7.296 +   AF.B.B0|=ZeroTable[HL.B.B1];
   7.297 +   break;
   7.298 + case 0x25:
   7.299 +   // SLA L
   7.300 +   AF.B.B0=(HL.B.B0&0x80?C_FLAG : 0);
   7.301 +   HL.B.B0<<=1;
   7.302 +   AF.B.B0|=ZeroTable[HL.B.B0];
   7.303 +   break;
   7.304 + case 0x26:
   7.305 +   // SLA (HL)
   7.306 +   tempValue=gbReadMemory(HL.W);
   7.307 +   AF.B.B0=(tempValue&0x80?C_FLAG : 0);
   7.308 +   tempValue<<=1;
   7.309 +   AF.B.B0|=ZeroTable[tempValue];
   7.310 +   gbWriteMemory(HL.W,tempValue);
   7.311 +   break;
   7.312 + case 0x27:
   7.313 +   // SLA A
   7.314 +   AF.B.B0=(AF.B.B1&0x80?C_FLAG : 0);
   7.315 +   AF.B.B1<<=1;
   7.316 +   AF.B.B0|=ZeroTable[AF.B.B1];
   7.317 +   break;
   7.318 + case 0x28:
   7.319 +   // SRA B
   7.320 +   AF.B.B0=(BC.B.B1&0x01 ? C_FLAG: 0);
   7.321 +   BC.B.B1=(BC.B.B1>>1)|(BC.B.B1&0x80);
   7.322 +   AF.B.B0|=ZeroTable[BC.B.B1];
   7.323 +   break;
   7.324 + case 0x29:
   7.325 +   // SRA C
   7.326 +   AF.B.B0=(BC.B.B0&0x01 ? C_FLAG: 0);
   7.327 +   BC.B.B0=(BC.B.B0>>1)|(BC.B.B0&0x80);
   7.328 +   AF.B.B0|=ZeroTable[BC.B.B0];
   7.329 +   break;
   7.330 + case 0x2a:
   7.331 +   // SRA D
   7.332 +   AF.B.B0=(DE.B.B1&0x01 ? C_FLAG: 0);
   7.333 +   DE.B.B1=(DE.B.B1>>1)|(DE.B.B1&0x80);
   7.334 +   AF.B.B0|=ZeroTable[DE.B.B1];
   7.335 +   break;
   7.336 + case 0x2b:
   7.337 +   // SRA E
   7.338 +   AF.B.B0=(DE.B.B0&0x01 ? C_FLAG: 0);
   7.339 +   DE.B.B0=(DE.B.B0>>1)|(DE.B.B0&0x80);
   7.340 +   AF.B.B0|=ZeroTable[DE.B.B0];
   7.341 +   break;
   7.342 + case 0x2c:
   7.343 +   // SRA H
   7.344 +   AF.B.B0=(HL.B.B1&0x01 ? C_FLAG: 0);
   7.345 +   HL.B.B1=(HL.B.B1>>1)|(HL.B.B1&0x80);
   7.346 +   AF.B.B0|=ZeroTable[HL.B.B1];
   7.347 +   break;
   7.348 + case 0x2d:
   7.349 +   // SRA L
   7.350 +   AF.B.B0=(HL.B.B0&0x01 ? C_FLAG: 0);
   7.351 +   HL.B.B0=(HL.B.B0>>1)|(HL.B.B0&0x80);
   7.352 +   AF.B.B0|=ZeroTable[HL.B.B0];
   7.353 +   break;
   7.354 + case 0x2e:
   7.355 +   // SRA (HL)
   7.356 +   tempValue=gbReadMemory(HL.W);
   7.357 +   AF.B.B0=(tempValue&0x01 ? C_FLAG: 0);
   7.358 +   tempValue=(tempValue>>1)|(tempValue&0x80);
   7.359 +   AF.B.B0|=ZeroTable[tempValue];
   7.360 +   gbWriteMemory(HL.W,tempValue);
   7.361 +   break;
   7.362 + case 0x2f:
   7.363 +   // SRA A
   7.364 +   AF.B.B0=(AF.B.B1&0x01 ? C_FLAG: 0);
   7.365 +   AF.B.B1=(AF.B.B1>>1)|(AF.B.B1&0x80);
   7.366 +   AF.B.B0|=ZeroTable[AF.B.B1];
   7.367 +   break;
   7.368 + case 0x30:
   7.369 +   // SWAP B
   7.370 +   BC.B.B1 = (BC.B.B1&0xf0)>>4 | (BC.B.B1&0x0f)<<4;
   7.371 +   AF.B.B0 = ZeroTable[BC.B.B1];
   7.372 +   break;
   7.373 + case 0x31:
   7.374 +   // SWAP C
   7.375 +   BC.B.B0 = (BC.B.B0&0xf0)>>4 | (BC.B.B0&0x0f)<<4;
   7.376 +   AF.B.B0 = ZeroTable[BC.B.B0];
   7.377 +   break;
   7.378 + case 0x32:
   7.379 +  // SWAP D
   7.380 +  DE.B.B1 = (DE.B.B1&0xf0)>>4 | (DE.B.B1&0x0f)<<4;
   7.381 +  AF.B.B0 = ZeroTable[DE.B.B1];
   7.382 +  break;
   7.383 + case 0x33:
   7.384 +   // SWAP E
   7.385 +   DE.B.B0 = (DE.B.B0&0xf0)>>4 | (DE.B.B0&0x0f)<<4;
   7.386 +   AF.B.B0 = ZeroTable[DE.B.B0];
   7.387 +   break;
   7.388 + case 0x34:
   7.389 +   // SWAP H
   7.390 +   HL.B.B1 = (HL.B.B1&0xf0)>>4 | (HL.B.B1&0x0f)<<4;
   7.391 +   AF.B.B0 = ZeroTable[HL.B.B1];
   7.392 +   break;
   7.393 + case 0x35:
   7.394 +   // SWAP L
   7.395 +   HL.B.B0 = (HL.B.B0&0xf0)>>4 | (HL.B.B0&0x0f)<<4;
   7.396 +   AF.B.B0 = ZeroTable[HL.B.B0];
   7.397 +   break;
   7.398 + case 0x36:
   7.399 +   // SWAP (HL)
   7.400 +   tempValue=gbReadMemory(HL.W);
   7.401 +   tempValue = (tempValue&0xf0)>>4 | (tempValue&0x0f)<<4;
   7.402 +   AF.B.B0 = ZeroTable[tempValue];
   7.403 +   gbWriteMemory(HL.W,tempValue);
   7.404 +   break;
   7.405 + case 0x37:
   7.406 +   // SWAP A
   7.407 +   AF.B.B1 = (AF.B.B1&0xf0)>>4 | (AF.B.B1&0x0f)<<4;
   7.408 +   AF.B.B0 = ZeroTable[AF.B.B1];
   7.409 +   break;
   7.410 + case 0x38:
   7.411 +   // SRL B
   7.412 +   AF.B.B0=(BC.B.B1&0x01)?C_FLAG:0;
   7.413 +   BC.B.B1>>=1;
   7.414 +   AF.B.B0|=ZeroTable[BC.B.B1];
   7.415 +   break;
   7.416 + case 0x39:
   7.417 +   // SRL C
   7.418 +   AF.B.B0=(BC.B.B0&0x01)?C_FLAG:0;
   7.419 +   BC.B.B0>>=1;
   7.420 +   AF.B.B0|=ZeroTable[BC.B.B0];
   7.421 +   break;
   7.422 + case 0x3a:
   7.423 +   // SRL D
   7.424 +   AF.B.B0=(DE.B.B1&0x01)?C_FLAG:0;
   7.425 +   DE.B.B1>>=1;
   7.426 +   AF.B.B0|=ZeroTable[DE.B.B1];
   7.427 +   break;
   7.428 + case 0x3b:
   7.429 +   // SRL E
   7.430 +   AF.B.B0=(DE.B.B0&0x01)?C_FLAG:0;
   7.431 +   DE.B.B0>>=1;
   7.432 +   AF.B.B0|=ZeroTable[DE.B.B0];
   7.433 +   break;
   7.434 + case 0x3c:
   7.435 +   // SRL H
   7.436 +   AF.B.B0=(HL.B.B1&0x01)?C_FLAG:0;
   7.437 +   HL.B.B1>>=1;
   7.438 +   AF.B.B0|=ZeroTable[HL.B.B1];
   7.439 +   break;
   7.440 + case 0x3d:
   7.441 +   // SRL L
   7.442 +   AF.B.B0=(HL.B.B0&0x01)?C_FLAG:0;
   7.443 +   HL.B.B0>>=1;
   7.444 +   AF.B.B0|=ZeroTable[HL.B.B0];
   7.445 +   break;
   7.446 + case 0x3e:
   7.447 +   // SRL (HL)
   7.448 +   tempValue=gbReadMemory(HL.W);
   7.449 +   AF.B.B0=(tempValue&0x01)?C_FLAG:0;
   7.450 +   tempValue>>=1;
   7.451 +   AF.B.B0|=ZeroTable[tempValue];
   7.452 +   gbWriteMemory(HL.W,tempValue);
   7.453 +   break;
   7.454 + case 0x3f:
   7.455 +   // SRL A
   7.456 +   AF.B.B0=(AF.B.B1&0x01)?C_FLAG:0;
   7.457 +   AF.B.B1>>=1;
   7.458 +   AF.B.B0|=ZeroTable[AF.B.B1];
   7.459 +   break;
   7.460 + case 0x40:
   7.461 +   // BIT 0,B
   7.462 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<0)? 0:Z_FLAG);
   7.463 +   break;
   7.464 + case 0x41:
   7.465 +   // BIT 0,C
   7.466 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<0)? 0:Z_FLAG);
   7.467 +   break;
   7.468 + case 0x42:
   7.469 +   // BIT 0,D
   7.470 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<0)? 0:Z_FLAG);
   7.471 +   break;
   7.472 + case 0x43:
   7.473 +   // BIT 0,E
   7.474 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<0)? 0:Z_FLAG);
   7.475 +   break;
   7.476 + case 0x44:
   7.477 +   // BIT 0,H
   7.478 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<0)? 0:Z_FLAG);
   7.479 +   break;
   7.480 + case 0x45:
   7.481 +   // BIT 0,L
   7.482 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<0)? 0:Z_FLAG);
   7.483 +   break;
   7.484 + case 0x46:
   7.485 +   // BIT 0,(HL)
   7.486 +   tempValue=gbReadMemory(HL.W);
   7.487 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<0)? 0:Z_FLAG);
   7.488 +   break;
   7.489 + case 0x47:
   7.490 +   // BIT 0,A
   7.491 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<0)? 0:Z_FLAG);
   7.492 +   break;
   7.493 + case 0x48:
   7.494 +   // BIT 1,B
   7.495 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<1)? 0:Z_FLAG);
   7.496 +   break;
   7.497 + case 0x49:
   7.498 +   // BIT 1,C
   7.499 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<1)? 0:Z_FLAG);
   7.500 +   break;
   7.501 + case 0x4a:
   7.502 +   // BIT 1,D
   7.503 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<1)? 0:Z_FLAG);
   7.504 +   break;
   7.505 + case 0x4b:
   7.506 +   // BIT 1,E
   7.507 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<1)? 0:Z_FLAG);
   7.508 +   break;
   7.509 + case 0x4c:
   7.510 +   // BIT 1,H
   7.511 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<1)? 0:Z_FLAG);
   7.512 +   break;
   7.513 + case 0x4d:
   7.514 +   // BIT 1,L
   7.515 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<1)? 0:Z_FLAG);
   7.516 +   break;
   7.517 + case 0x4e:
   7.518 +   // BIT 1,(HL)
   7.519 +   tempValue=gbReadMemory(HL.W);
   7.520 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<1)? 0:Z_FLAG);
   7.521 +   break;
   7.522 + case 0x4f:
   7.523 +   // BIT 1,A
   7.524 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<1)? 0:Z_FLAG);
   7.525 +   break;
   7.526 + case 0x50:
   7.527 +   // BIT 2,B
   7.528 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<2)? 0:Z_FLAG);
   7.529 +   break;
   7.530 + case 0x51:
   7.531 +   // BIT 2,C
   7.532 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<2)? 0:Z_FLAG);
   7.533 +   break;
   7.534 + case 0x52:
   7.535 +   // BIT 2,D
   7.536 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<2)? 0:Z_FLAG);
   7.537 +   break;
   7.538 + case 0x53:
   7.539 +   // BIT 2,E
   7.540 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<2)? 0:Z_FLAG);
   7.541 +   break;
   7.542 + case 0x54:
   7.543 +   // BIT 2,H
   7.544 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<2)? 0:Z_FLAG);
   7.545 +   break;
   7.546 + case 0x55:
   7.547 +   // BIT 2,L
   7.548 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<2)? 0:Z_FLAG);
   7.549 +   break;
   7.550 + case 0x56:
   7.551 +   // BIT 2,(HL)
   7.552 +   tempValue=gbReadMemory(HL.W);
   7.553 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<2)? 0:Z_FLAG);
   7.554 +   break;
   7.555 + case 0x57:
   7.556 +   // BIT 2,A
   7.557 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<2)? 0:Z_FLAG);
   7.558 +   break;
   7.559 + case 0x58:
   7.560 +   // BIT 3,B
   7.561 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<3)? 0:Z_FLAG);
   7.562 +   break;
   7.563 + case 0x59:
   7.564 +   // BIT 3,C
   7.565 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<3)? 0:Z_FLAG);
   7.566 +   break;
   7.567 + case 0x5a:
   7.568 +   // BIT 3,D
   7.569 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<3)? 0:Z_FLAG);
   7.570 +   break;
   7.571 + case 0x5b:
   7.572 +   // BIT 3,E
   7.573 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<3)? 0:Z_FLAG);
   7.574 +   break;
   7.575 + case 0x5c:
   7.576 +   // BIT 3,H
   7.577 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<3)? 0:Z_FLAG);
   7.578 +   break;
   7.579 + case 0x5d:
   7.580 +   // BIT 3,L
   7.581 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<3)? 0:Z_FLAG);
   7.582 +   break;
   7.583 + case 0x5e:
   7.584 +   // BIT 3,(HL)
   7.585 +   tempValue=gbReadMemory(HL.W);
   7.586 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<3)? 0:Z_FLAG);
   7.587 +   break;
   7.588 + case 0x5f:
   7.589 +   // BIT 3,A
   7.590 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<3)? 0:Z_FLAG);
   7.591 +   break;
   7.592 + case 0x60:
   7.593 +   // BIT 4,B
   7.594 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<4)? 0:Z_FLAG);
   7.595 +   break;
   7.596 + case 0x61:
   7.597 +   // BIT 4,C
   7.598 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<4)? 0:Z_FLAG);
   7.599 +   break;
   7.600 + case 0x62:
   7.601 +   // BIT 4,D
   7.602 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<4)? 0:Z_FLAG);
   7.603 +   break;
   7.604 + case 0x63:
   7.605 +   // BIT 4,E
   7.606 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<4)? 0:Z_FLAG);
   7.607 +   break;
   7.608 + case 0x64:
   7.609 +   // BIT 4,H
   7.610 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<4)? 0:Z_FLAG);
   7.611 +   break;
   7.612 + case 0x65:
   7.613 +   // BIT 4,L
   7.614 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<4)? 0:Z_FLAG);
   7.615 +   break;
   7.616 + case 0x66:
   7.617 +   // BIT 4,(HL)
   7.618 +   tempValue=gbReadMemory(HL.W);
   7.619 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<4)? 0:Z_FLAG);
   7.620 +   break;
   7.621 + case 0x67:
   7.622 +   // BIT 4,A
   7.623 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<4)? 0:Z_FLAG);
   7.624 +   break;
   7.625 + case 0x68:
   7.626 +   // BIT 5,B
   7.627 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<5)? 0:Z_FLAG);
   7.628 +   break;
   7.629 + case 0x69:
   7.630 +   // BIT 5,C
   7.631 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<5)? 0:Z_FLAG);
   7.632 +   break;
   7.633 + case 0x6a:
   7.634 +   // BIT 5,D
   7.635 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<5)? 0:Z_FLAG);
   7.636 +   break;
   7.637 + case 0x6b:
   7.638 +   // BIT 5,E
   7.639 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<5)? 0:Z_FLAG);
   7.640 +   break;
   7.641 + case 0x6c:
   7.642 +   // BIT 5,H
   7.643 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<5)? 0:Z_FLAG);
   7.644 +   break;
   7.645 + case 0x6d:
   7.646 +   // BIT 5,L
   7.647 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<5)? 0:Z_FLAG);
   7.648 +   break;
   7.649 + case 0x6e:
   7.650 +   // BIT 5,(HL)
   7.651 +   tempValue=gbReadMemory(HL.W);
   7.652 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<5)? 0:Z_FLAG);
   7.653 +   break;
   7.654 + case 0x6f:
   7.655 +   // BIT 5,A
   7.656 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<5)? 0:Z_FLAG);
   7.657 +   break;
   7.658 + case 0x70:
   7.659 +   // BIT 6,B
   7.660 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<6)? 0:Z_FLAG);
   7.661 +   break;
   7.662 + case 0x71:
   7.663 +   // BIT 6,C
   7.664 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<6)? 0:Z_FLAG);
   7.665 +   break;
   7.666 + case 0x72:
   7.667 +   // BIT 6,D
   7.668 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<6)? 0:Z_FLAG);
   7.669 +   break;
   7.670 + case 0x73:
   7.671 +   // BIT 6,E
   7.672 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<6)? 0:Z_FLAG);
   7.673 +   break;
   7.674 + case 0x74:
   7.675 +   // BIT 6,H
   7.676 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<6)? 0:Z_FLAG);
   7.677 +   break;
   7.678 + case 0x75:
   7.679 +   // BIT 6,L
   7.680 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<6)? 0:Z_FLAG);
   7.681 +   break;
   7.682 + case 0x76:
   7.683 +   // BIT 6,(HL)
   7.684 +   tempValue=gbReadMemory(HL.W);
   7.685 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<6)? 0:Z_FLAG);
   7.686 +   break;
   7.687 + case 0x77:
   7.688 +   // BIT 6,A
   7.689 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<6)? 0:Z_FLAG);
   7.690 +   break;
   7.691 + case 0x78:
   7.692 +   // BIT 7,B
   7.693 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<7)? 0:Z_FLAG);
   7.694 +   break;
   7.695 + case 0x79:
   7.696 +   // BIT 7,C
   7.697 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<7)? 0:Z_FLAG);
   7.698 +   break;
   7.699 + case 0x7a:
   7.700 +   // BIT 7,D
   7.701 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<7)? 0:Z_FLAG);
   7.702 +   break;
   7.703 + case 0x7b:
   7.704 +   // BIT 7,E
   7.705 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<7)? 0:Z_FLAG);
   7.706 +   break;
   7.707 + case 0x7c:
   7.708 +   // BIT 7,H
   7.709 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<7)? 0:Z_FLAG);
   7.710 +   break;
   7.711 + case 0x7d:
   7.712 +   // BIT 7,L
   7.713 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<7)? 0:Z_FLAG);
   7.714 +   break;
   7.715 + case 0x7e:
   7.716 +   // BIT 7,(HL)
   7.717 +   tempValue=gbReadMemory(HL.W);
   7.718 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<7)? 0:Z_FLAG);
   7.719 +   break;
   7.720 + case 0x7f:
   7.721 +   // BIT 7,A
   7.722 +   AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<7)? 0:Z_FLAG);
   7.723 +   break;
   7.724 + case 0x80:
   7.725 +   // RES 0,B
   7.726 +   BC.B.B1&=~(1<<0);
   7.727 +   break;
   7.728 + case 0x81:
   7.729 +   // RES 0,C
   7.730 +   BC.B.B0&=~(1<<0);
   7.731 +   break;
   7.732 + case 0x82:
   7.733 +   // RES 0,D
   7.734 +   DE.B.B1&=~(1<<0);
   7.735 +   break;
   7.736 + case 0x83:
   7.737 +   // RES 0,E
   7.738 +   DE.B.B0&=~(1<<0);
   7.739 +   break;
   7.740 + case 0x84:
   7.741 +   // RES 0,H
   7.742 +   HL.B.B1&=~(1<<0);
   7.743 +   break;
   7.744 + case 0x85:
   7.745 +   // RES 0,L
   7.746 +   HL.B.B0&=~(1<<0);
   7.747 +   break;
   7.748 + case 0x86:
   7.749 +   // RES 0,(HL)
   7.750 +   tempValue=gbReadMemory(HL.W);
   7.751 +   tempValue&=~(1<<0);
   7.752 +   gbWriteMemory(HL.W,tempValue);
   7.753 +   break;
   7.754 + case 0x87:
   7.755 +   // RES 0,A
   7.756 +   AF.B.B1&=~(1<<0);
   7.757 +   break;
   7.758 + case 0x88:
   7.759 +   // RES 1,B
   7.760 +   BC.B.B1&=~(1<<1);
   7.761 +   break;
   7.762 + case 0x89:
   7.763 +   // RES 1,C
   7.764 +   BC.B.B0&=~(1<<1);
   7.765 +   break;
   7.766 + case 0x8a:
   7.767 +   // RES 1,D
   7.768 +   DE.B.B1&=~(1<<1);
   7.769 +   break;
   7.770 + case 0x8b:
   7.771 +   // RES 1,E
   7.772 +   DE.B.B0&=~(1<<1);
   7.773 +   break;
   7.774 + case 0x8c:
   7.775 +   // RES 1,H
   7.776 +   HL.B.B1&=~(1<<1);
   7.777 +   break;
   7.778 + case 0x8d:
   7.779 +   // RES 1,L
   7.780 +   HL.B.B0&=~(1<<1);
   7.781 +   break;
   7.782 + case 0x8e:
   7.783 +   // RES 1,(HL)
   7.784 +   tempValue=gbReadMemory(HL.W);
   7.785 +   tempValue&=~(1<<1);
   7.786 +   gbWriteMemory(HL.W,tempValue);
   7.787 +   break;
   7.788 + case 0x8f:
   7.789 +   // RES 1,A
   7.790 +   AF.B.B1&=~(1<<1);
   7.791 +   break;
   7.792 + case 0x90:
   7.793 +   // RES 2,B
   7.794 +   BC.B.B1&=~(1<<2);
   7.795 +   break;
   7.796 + case 0x91:
   7.797 +   // RES 2,C
   7.798 +   BC.B.B0&=~(1<<2);
   7.799 +   break;
   7.800 + case 0x92:
   7.801 +   // RES 2,D
   7.802 +   DE.B.B1&=~(1<<2);
   7.803 +   break;
   7.804 + case 0x93:
   7.805 +   // RES 2,E
   7.806 +   DE.B.B0&=~(1<<2);
   7.807 +   break;
   7.808 + case 0x94:
   7.809 +   // RES 2,H
   7.810 +   HL.B.B1&=~(1<<2);
   7.811 +   break;
   7.812 + case 0x95:
   7.813 +   // RES 2,L
   7.814 +   HL.B.B0&=~(1<<2);
   7.815 +   break;
   7.816 + case 0x96:
   7.817 +   // RES 2,(HL)
   7.818 +   tempValue=gbReadMemory(HL.W);
   7.819 +   tempValue&=~(1<<2);
   7.820 +   gbWriteMemory(HL.W,tempValue);
   7.821 +   break;
   7.822 + case 0x97:
   7.823 +   // RES 2,A
   7.824 +   AF.B.B1&=~(1<<2);
   7.825 +   break;
   7.826 + case 0x98:
   7.827 +   // RES 3,B
   7.828 +   BC.B.B1&=~(1<<3);
   7.829 +   break;
   7.830 + case 0x99:
   7.831 +   // RES 3,C
   7.832 +   BC.B.B0&=~(1<<3);
   7.833 +   break;
   7.834 + case 0x9a:
   7.835 +   // RES 3,D
   7.836 +   DE.B.B1&=~(1<<3);
   7.837 +   break;
   7.838 + case 0x9b:
   7.839 +   // RES 3,E
   7.840 +   DE.B.B0&=~(1<<3);
   7.841 +   break;
   7.842 + case 0x9c:
   7.843 +   // RES 3,H
   7.844 +   HL.B.B1&=~(1<<3);
   7.845 +   break;
   7.846 + case 0x9d:
   7.847 +   // RES 3,L
   7.848 +   HL.B.B0&=~(1<<3);
   7.849 +   break;
   7.850 + case 0x9e:
   7.851 +   // RES 3,(HL)
   7.852 +   tempValue=gbReadMemory(HL.W);
   7.853 +   tempValue&=~(1<<3);
   7.854 +   gbWriteMemory(HL.W,tempValue);
   7.855 +   break;
   7.856 + case 0x9f:
   7.857 +   // RES 3,A
   7.858 +   AF.B.B1&=~(1<<3);
   7.859 +   break;
   7.860 + case 0xa0:
   7.861 +   // RES 4,B
   7.862 +   BC.B.B1&=~(1<<4);
   7.863 +   break;
   7.864 + case 0xa1:
   7.865 +   // RES 4,C
   7.866 +   BC.B.B0&=~(1<<4);
   7.867 +   break;
   7.868 + case 0xa2:
   7.869 +   // RES 4,D
   7.870 +   DE.B.B1&=~(1<<4);
   7.871 +   break;
   7.872 + case 0xa3:
   7.873 +   // RES 4,E
   7.874 +   DE.B.B0&=~(1<<4);
   7.875 +   break;
   7.876 + case 0xa4:
   7.877 +   // RES 4,H
   7.878 +   HL.B.B1&=~(1<<4);
   7.879 +   break;
   7.880 + case 0xa5:
   7.881 +   // RES 4,L
   7.882 +   HL.B.B0&=~(1<<4);
   7.883 +   break;
   7.884 + case 0xa6:
   7.885 +   // RES 4,(HL)
   7.886 +   tempValue=gbReadMemory(HL.W);
   7.887 +   tempValue&=~(1<<4);
   7.888 +   gbWriteMemory(HL.W,tempValue);
   7.889 +   break;
   7.890 + case 0xa7:
   7.891 +   // RES 4,A
   7.892 +   AF.B.B1&=~(1<<4);
   7.893 +   break;
   7.894 + case 0xa8:
   7.895 +   // RES 5,B
   7.896 +   BC.B.B1&=~(1<<5);
   7.897 +   break;
   7.898 + case 0xa9:
   7.899 +   // RES 5,C
   7.900 +   BC.B.B0&=~(1<<5);
   7.901 +   break;
   7.902 + case 0xaa:
   7.903 +   // RES 5,D
   7.904 +   DE.B.B1&=~(1<<5);
   7.905 +   break;
   7.906 + case 0xab:
   7.907 +   // RES 5,E
   7.908 +   DE.B.B0&=~(1<<5);
   7.909 +   break;
   7.910 + case 0xac:
   7.911 +   // RES 5,H
   7.912 +   HL.B.B1&=~(1<<5);
   7.913 +   break;
   7.914 + case 0xad:
   7.915 +   // RES 5,L
   7.916 +   HL.B.B0&=~(1<<5);
   7.917 +   break;
   7.918 + case 0xae:
   7.919 +   // RES 5,(HL)
   7.920 +   tempValue=gbReadMemory(HL.W);
   7.921 +   tempValue&=~(1<<5);
   7.922 +   gbWriteMemory(HL.W,tempValue);
   7.923 +   break;
   7.924 + case 0xaf:
   7.925 +   // RES 5,A
   7.926 +   AF.B.B1&=~(1<<5);
   7.927 +   break;
   7.928 + case 0xb0:
   7.929 +   // RES 6,B
   7.930 +   BC.B.B1&=~(1<<6);
   7.931 +   break;
   7.932 + case 0xb1:
   7.933 +   // RES 6,C
   7.934 +   BC.B.B0&=~(1<<6);
   7.935 +   break;
   7.936 + case 0xb2:
   7.937 +   // RES 6,D
   7.938 +   DE.B.B1&=~(1<<6);
   7.939 +   break;
   7.940 + case 0xb3:
   7.941 +   // RES 6,E
   7.942 +   DE.B.B0&=~(1<<6);
   7.943 +   break;
   7.944 + case 0xb4:
   7.945 +   // RES 6,H
   7.946 +   HL.B.B1&=~(1<<6);
   7.947 +   break;
   7.948 + case 0xb5:
   7.949 +   // RES 6,L
   7.950 +   HL.B.B0&=~(1<<6);
   7.951 +   break;
   7.952 + case 0xb6:
   7.953 +   // RES 6,(HL)
   7.954 +   tempValue=gbReadMemory(HL.W);
   7.955 +   tempValue&=~(1<<6);
   7.956 +   gbWriteMemory(HL.W,tempValue);
   7.957 +   break;
   7.958 + case 0xb7:
   7.959 +   // RES 6,A
   7.960 +   AF.B.B1&=~(1<<6);
   7.961 +   break;
   7.962 + case 0xb8:
   7.963 +   // RES 7,B
   7.964 +   BC.B.B1&=~(1<<7);
   7.965 +   break;
   7.966 + case 0xb9:
   7.967 +   // RES 7,C
   7.968 +   BC.B.B0&=~(1<<7);
   7.969 +   break;
   7.970 + case 0xba:
   7.971 +   // RES 7,D
   7.972 +   DE.B.B1&=~(1<<7);
   7.973 +   break;
   7.974 + case 0xbb:
   7.975 +   // RES 7,E
   7.976 +   DE.B.B0&=~(1<<7);
   7.977 +   break;
   7.978 + case 0xbc:
   7.979 +   // RES 7,H
   7.980 +   HL.B.B1&=~(1<<7);
   7.981 +   break;
   7.982 + case 0xbd:
   7.983 +   // RES 7,L
   7.984 +   HL.B.B0&=~(1<<7);
   7.985 +   break;
   7.986 + case 0xbe:
   7.987 +   // RES 7,(HL)
   7.988 +   tempValue=gbReadMemory(HL.W);
   7.989 +   tempValue&=~(1<<7);
   7.990 +   gbWriteMemory(HL.W,tempValue);
   7.991 +   break;
   7.992 + case 0xbf:
   7.993 +   // RES 7,A
   7.994 +   AF.B.B1&=~(1<<7);
   7.995 +   break;
   7.996 + case 0xc0:
   7.997 +   // SET 0,B
   7.998 +   BC.B.B1|=1<<0;
   7.999 +   break;
  7.1000 + case 0xc1:
  7.1001 +   // SET 0,C
  7.1002 +   BC.B.B0|=1<<0;
  7.1003 +   break;
  7.1004 + case 0xc2:
  7.1005 +   // SET 0,D
  7.1006 +   DE.B.B1|=1<<0;
  7.1007 +   break;
  7.1008 + case 0xc3:
  7.1009 +   // SET 0,E
  7.1010 +   DE.B.B0|=1<<0;
  7.1011 +   break;
  7.1012 + case 0xc4:
  7.1013 +   // SET 0,H
  7.1014 +   HL.B.B1|=1<<0;
  7.1015 +   break;
  7.1016 + case 0xc5:
  7.1017 +   // SET 0,L
  7.1018 +   HL.B.B0|=1<<0;
  7.1019 +   break;
  7.1020 + case 0xc6:
  7.1021 +   // SET 0,(HL)
  7.1022 +   tempValue=gbReadMemory(HL.W);
  7.1023 +   tempValue|=1<<0;
  7.1024 +   gbWriteMemory(HL.W,tempValue);
  7.1025 +   break;
  7.1026 + case 0xc7:
  7.1027 +   // SET 0,A
  7.1028 +   AF.B.B1|=1<<0;
  7.1029 +   break;
  7.1030 + case 0xc8:
  7.1031 +   // SET 1,B
  7.1032 +   BC.B.B1|=1<<1;
  7.1033 +   break;
  7.1034 + case 0xc9:
  7.1035 +   // SET 1,C
  7.1036 +   BC.B.B0|=1<<1;
  7.1037 +   break;
  7.1038 + case 0xca:
  7.1039 +   // SET 1,D
  7.1040 +   DE.B.B1|=1<<1;
  7.1041 +   break;
  7.1042 + case 0xcb:
  7.1043 +   // SET 1,E
  7.1044 +   DE.B.B0|=1<<1;
  7.1045 +   break;
  7.1046 + case 0xcc:
  7.1047 +   // SET 1,H
  7.1048 +   HL.B.B1|=1<<1;
  7.1049 +   break;
  7.1050 + case 0xcd:
  7.1051 +   // SET 1,L
  7.1052 +   HL.B.B0|=1<<1;
  7.1053 +   break;
  7.1054 + case 0xce:
  7.1055 +   // SET 1,(HL)
  7.1056 +   tempValue=gbReadMemory(HL.W);
  7.1057 +   tempValue|=1<<1;
  7.1058 +   gbWriteMemory(HL.W,tempValue);
  7.1059 +   break;
  7.1060 + case 0xcf:
  7.1061 +   // SET 1,A
  7.1062 +   AF.B.B1|=1<<1;
  7.1063 +   break;
  7.1064 + case 0xd0:
  7.1065 +   // SET 2,B
  7.1066 +   BC.B.B1|=1<<2;
  7.1067 +   break;
  7.1068 + case 0xd1:
  7.1069 +   // SET 2,C
  7.1070 +   BC.B.B0|=1<<2;
  7.1071 +   break;
  7.1072 + case 0xd2:
  7.1073 +   // SET 2,D
  7.1074 +   DE.B.B1|=1<<2;
  7.1075 +   break;
  7.1076 + case 0xd3:
  7.1077 +   // SET 2,E
  7.1078 +   DE.B.B0|=1<<2;
  7.1079 +   break;
  7.1080 + case 0xd4:
  7.1081 +   // SET 2,H
  7.1082 +   HL.B.B1|=1<<2;
  7.1083 +   break;
  7.1084 + case 0xd5:
  7.1085 +   // SET 2,L
  7.1086 +   HL.B.B0|=1<<2;
  7.1087 +   break;
  7.1088 + case 0xd6:
  7.1089 +   // SET 2,(HL)
  7.1090 +   tempValue=gbReadMemory(HL.W);
  7.1091 +   tempValue|=1<<2;
  7.1092 +   gbWriteMemory(HL.W,tempValue);
  7.1093 +   break;
  7.1094 + case 0xd7:
  7.1095 +   // SET 2,A
  7.1096 +   AF.B.B1|=1<<2;
  7.1097 +   break;
  7.1098 + case 0xd8:
  7.1099 +   // SET 3,B
  7.1100 +   BC.B.B1|=1<<3;
  7.1101 +   break;
  7.1102 + case 0xd9:
  7.1103 +   // SET 3,C
  7.1104 +   BC.B.B0|=1<<3;
  7.1105 +   break;
  7.1106 + case 0xda:
  7.1107 +   // SET 3,D
  7.1108 +   DE.B.B1|=1<<3;
  7.1109 +   break;
  7.1110 + case 0xdb:
  7.1111 +   // SET 3,E
  7.1112 +   DE.B.B0|=1<<3;
  7.1113 +   break;
  7.1114 + case 0xdc:
  7.1115 +   // SET 3,H
  7.1116 +   HL.B.B1|=1<<3;
  7.1117 +   break;
  7.1118 + case 0xdd:
  7.1119 +   // SET 3,L
  7.1120 +   HL.B.B0|=1<<3;
  7.1121 +   break;
  7.1122 + case 0xde:
  7.1123 +   // SET 3,(HL)
  7.1124 +   tempValue=gbReadMemory(HL.W);
  7.1125 +   tempValue|=1<<3;
  7.1126 +   gbWriteMemory(HL.W,tempValue);
  7.1127 +   break;
  7.1128 + case 0xdf:
  7.1129 +   // SET 3,A
  7.1130 +   AF.B.B1|=1<<3;
  7.1131 +   break;
  7.1132 + case 0xe0:
  7.1133 +   // SET 4,B
  7.1134 +   BC.B.B1|=1<<4;
  7.1135 +   break;
  7.1136 + case 0xe1:
  7.1137 +   // SET 4,C
  7.1138 +   BC.B.B0|=1<<4;
  7.1139 +   break;
  7.1140 + case 0xe2:
  7.1141 +   // SET 4,D
  7.1142 +   DE.B.B1|=1<<4;
  7.1143 +   break;
  7.1144 + case 0xe3:
  7.1145 +   // SET 4,E
  7.1146 +   DE.B.B0|=1<<4;
  7.1147 +   break;
  7.1148 + case 0xe4:
  7.1149 +   // SET 4,H
  7.1150 +   HL.B.B1|=1<<4;
  7.1151 +   break;
  7.1152 + case 0xe5:
  7.1153 +   // SET 4,L
  7.1154 +   HL.B.B0|=1<<4;
  7.1155 +   break;
  7.1156 + case 0xe6:
  7.1157 +   // SET 4,(HL)
  7.1158 +   tempValue=gbReadMemory(HL.W);
  7.1159 +   tempValue|=1<<4;
  7.1160 +   gbWriteMemory(HL.W,tempValue);
  7.1161 +   break;
  7.1162 + case 0xe7:
  7.1163 +   // SET 4,A
  7.1164 +   AF.B.B1|=1<<4;
  7.1165 +   break;
  7.1166 + case 0xe8:
  7.1167 +   // SET 5,B
  7.1168 +   BC.B.B1|=1<<5;
  7.1169 +   break;
  7.1170 + case 0xe9:
  7.1171 +   // SET 5,C
  7.1172 +   BC.B.B0|=1<<5;
  7.1173 +   break;
  7.1174 + case 0xea:
  7.1175 +   // SET 5,D
  7.1176 +   DE.B.B1|=1<<5;
  7.1177 +   break;
  7.1178 + case 0xeb:
  7.1179 +   // SET 5,E
  7.1180 +   DE.B.B0|=1<<5;
  7.1181 +   break;
  7.1182 + case 0xec:
  7.1183 +   // SET 5,H
  7.1184 +   HL.B.B1|=1<<5;
  7.1185 +   break;
  7.1186 + case 0xed:
  7.1187 +   // SET 5,L
  7.1188 +   HL.B.B0|=1<<5;
  7.1189 +   break;
  7.1190 + case 0xee:
  7.1191 +   // SET 5,(HL)
  7.1192 +   tempValue=gbReadMemory(HL.W);
  7.1193 +   tempValue|=1<<5;
  7.1194 +   gbWriteMemory(HL.W,tempValue);
  7.1195 +   break;
  7.1196 + case 0xef:
  7.1197 +   // SET 5,A
  7.1198 +   AF.B.B1|=1<<5;
  7.1199 +   break;
  7.1200 + case 0xf0:
  7.1201 +   // SET 6,B
  7.1202 +   BC.B.B1|=1<<6;
  7.1203 +   break;
  7.1204 + case 0xf1:
  7.1205 +   // SET 6,C
  7.1206 +   BC.B.B0|=1<<6;
  7.1207 +   break;
  7.1208 + case 0xf2:
  7.1209 +   // SET 6,D
  7.1210 +   DE.B.B1|=1<<6;
  7.1211 +   break;
  7.1212 + case 0xf3:
  7.1213 +   // SET 6,E
  7.1214 +   DE.B.B0|=1<<6;
  7.1215 +   break;
  7.1216 + case 0xf4:
  7.1217 +   // SET 6,H
  7.1218 +   HL.B.B1|=1<<6;
  7.1219 +   break;
  7.1220 + case 0xf5:
  7.1221 +   // SET 6,L
  7.1222 +   HL.B.B0|=1<<6;
  7.1223 +   break;
  7.1224 + case 0xf6:
  7.1225 +   // SET 6,(HL)
  7.1226 +   tempValue=gbReadMemory(HL.W);
  7.1227 +   tempValue|=1<<6;
  7.1228 +   gbWriteMemory(HL.W,tempValue);
  7.1229 +   break;
  7.1230 + case 0xf7:
  7.1231 +   // SET 6,A
  7.1232 +   AF.B.B1|=1<<6;
  7.1233 +   break;
  7.1234 + case 0xf8:
  7.1235 +   // SET 7,B
  7.1236 +   BC.B.B1|=1<<7;
  7.1237 +   break;
  7.1238 + case 0xf9:
  7.1239 +   // SET 7,C
  7.1240 +   BC.B.B0|=1<<7;
  7.1241 +   break;
  7.1242 + case 0xfa:
  7.1243 +   // SET 7,D
  7.1244 +   DE.B.B1|=1<<7;
  7.1245 +   break;
  7.1246 + case 0xfb:
  7.1247 +   // SET 7,E
  7.1248 +   DE.B.B0|=1<<7;
  7.1249 +   break;
  7.1250 + case 0xfc:
  7.1251 +   // SET 7,H
  7.1252 +   HL.B.B1|=1<<7;
  7.1253 +   break;
  7.1254 + case 0xfd:
  7.1255 +   // SET 7,L
  7.1256 +   HL.B.B0|=1<<7;
  7.1257 +   break;
  7.1258 + case 0xfe:
  7.1259 +   // SET 7,(HL)
  7.1260 +   tempValue=gbReadMemory(HL.W);
  7.1261 +   tempValue|=1<<7;
  7.1262 +   gbWriteMemory(HL.W,tempValue);
  7.1263 +   break;
  7.1264 + case 0xff:
  7.1265 +   // SET 7,A
  7.1266 +   AF.B.B1|=1<<7;
  7.1267 +   break;
  7.1268 + default:
  7.1269 +   systemMessage(0, N_("Unknown opcode %02x at %04x"),
  7.1270 +                 gbReadOpcode(PC.W-1),PC.W-1);
  7.1271 +   emulating = false;
  7.1272 +   return;
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/gb/gbDis.cpp	Sat Mar 03 11:44:47 2012 -0600
     8.3 @@ -0,0 +1,239 @@
     8.4 +#include <cstdio>
     8.5 +#include <cstring>
     8.6 +
     8.7 +#include "gbGlobals.h"
     8.8 +
     8.9 +typedef struct
    8.10 +{
    8.11 +	u8    mask;
    8.12 +	u8    value;
    8.13 +	char *mnen;
    8.14 +} GBOPCODE;
    8.15 +
    8.16 +static char *registers[] =
    8.17 +{ "B", "C", "D", "E", "H", "L", "(HL)", "A" };
    8.18 +
    8.19 +static char *registers16[] =
    8.20 +{ "BC", "DE", "HL", "SP", // for some operations
    8.21 +  "BC", "DE", "HL", "AF" };   // for push/pop
    8.22 +
    8.23 +static char *cond[] =
    8.24 +{ "NZ", "Z", "NC", "C" };
    8.25 +
    8.26 +static char hexDigits[16] = {
    8.27 +	'0', '1', '2', '3', '4', '5', '6', '7',
    8.28 +	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
    8.29 +};
    8.30 +
    8.31 +static GBOPCODE opcodes[] = {
    8.32 +	{ 0xff, 0x00, "NOP"            },
    8.33 +	{ 0xcf, 0x01, "LD %R4,%W"      },
    8.34 +	{ 0xff, 0x02, "LD (BC),A"      },
    8.35 +	{ 0xcf, 0x03, "INC %R4"        },
    8.36 +	{ 0xc7, 0x04, "INC %r3"        },
    8.37 +	{ 0xc7, 0x05, "DEC %r3"        },
    8.38 +	{ 0xc7, 0x06, "LD %r3,%B"      },
    8.39 +	{ 0xff, 0x07, "RLCA"           },
    8.40 +	{ 0xff, 0x08, "LD (%W),SP"     },
    8.41 +	{ 0xcf, 0x09, "ADD HL,%R4"     },
    8.42 +	{ 0xff, 0x0a, "LD A,(BC)"      },
    8.43 +	{ 0xcf, 0x0b, "DEC %R4"        },
    8.44 +	{ 0xff, 0x0f, "RRCA"           },
    8.45 +	{ 0xff, 0x10, "STOP"           },
    8.46 +	{ 0xff, 0x12, "LD (DE),A"      },
    8.47 +	{ 0xff, 0x17, "RLA"            },
    8.48 +	{ 0xff, 0x18, "JR %d"          },
    8.49 +	{ 0xff, 0x1a, "LD A,(DE)"      },
    8.50 +	{ 0xff, 0x1f, "RRA"            },
    8.51 +	{ 0xe7, 0x20, "JR %c3,%d"      },
    8.52 +	{ 0xff, 0x22, "LDI (HL),A"     },
    8.53 +	{ 0xff, 0x27, "DAA"            },
    8.54 +	{ 0xff, 0x2a, "LDI A,(HL)"     },
    8.55 +	{ 0xff, 0x2f, "CPL"            },
    8.56 +	{ 0xff, 0x32, "LDD (HL),A"     },
    8.57 +	{ 0xff, 0x37, "SCF"            },
    8.58 +	{ 0xff, 0x3a, "LDD A,(HL)"     },
    8.59 +	{ 0xff, 0x3f, "CCF"            },
    8.60 +	{ 0xff, 0x76, "HALT"           },
    8.61 +	{ 0xc0, 0x40, "LD %r3,%r0"     },
    8.62 +	{ 0xf8, 0x80, "ADD A,%r0"      },
    8.63 +	{ 0xf8, 0x88, "ADC A,%r0"      },
    8.64 +	{ 0xf8, 0x90, "SUB %r0"        },
    8.65 +	{ 0xf8, 0x98, "SBC A,%r0"      },
    8.66 +	{ 0xf8, 0xa0, "AND %r0"        },
    8.67 +	{ 0xf8, 0xa8, "XOR %r0"        },
    8.68 +	{ 0xf8, 0xb0, "OR %r0"         },
    8.69 +	{ 0xf8, 0xb8, "CP %r0"         },
    8.70 +	{ 0xe7, 0xc0, "RET %c3"        },
    8.71 +	{ 0xcf, 0xc1, "POP %t4"        },
    8.72 +	{ 0xe7, 0xc2, "JP %c3,%W"      },
    8.73 +	{ 0xff, 0xc3, "JP %W"          },
    8.74 +	{ 0xe7, 0xc4, "CALL %c3,%W"    },
    8.75 +	{ 0xcf, 0xc5, "PUSH %t4"       },
    8.76 +	{ 0xff, 0xc6, "ADD A,%B"       },
    8.77 +	{ 0xc7, 0xc7, "RST %P"         },
    8.78 +	{ 0xff, 0xc9, "RET"            },
    8.79 +	{ 0xff, 0xcd, "CALL %W"        },
    8.80 +	{ 0xff, 0xce, "ADC %B"         },
    8.81 +	{ 0xff, 0xd6, "SUB %B"         },
    8.82 +	{ 0xff, 0xd9, "RETI"           },
    8.83 +	{ 0xff, 0xde, "SBC %B"         },
    8.84 +	{ 0xff, 0xe0, "LD (FF%B),A"    },
    8.85 +	{ 0xff, 0xe2, "LD (FF00h+C),A" },
    8.86 +	{ 0xff, 0xe6, "AND %B"         },
    8.87 +	{ 0xff, 0xe8, "ADD SP,%D"      },
    8.88 +	{ 0xff, 0xe9, "LD PC,HL"       },
    8.89 +	{ 0xff, 0xea, "LD (%W),A"      },
    8.90 +	{ 0xff, 0xee, "XOR %B"         },
    8.91 +	{ 0xff, 0xf0, "LD A,(FF%B)"    },
    8.92 +	{ 0xff, 0xf2, "LD A,(FF00h+C)" },
    8.93 +	{ 0xff, 0xf3, "DI"             },
    8.94 +	{ 0xff, 0xf6, "OR %B"          },
    8.95 +	{ 0xff, 0xf8, "LD HL,SP%D"     },
    8.96 +	{ 0xff, 0xf9, "LD SP,HL"       },
    8.97 +	{ 0xff, 0xfa, "LD A,(%W)"      },
    8.98 +	{ 0xff, 0xfb, "EI"             },
    8.99 +	{ 0xff, 0xfe, "CP %B"          },
   8.100 +	{ 0x00, 0x00, "DB %B"          }
   8.101 +};
   8.102 +
   8.103 +static GBOPCODE cbOpcodes[] = {
   8.104 +	{ 0xf8, 0x00, "RLC %r0"    },
   8.105 +	{ 0xf8, 0x08, "RRC %r0"    },
   8.106 +	{ 0xf8, 0x10, "RL %r0"     },
   8.107 +	{ 0xf8, 0x18, "RR %r0"     },
   8.108 +	{ 0xf8, 0x20, "SLA %r0"    },
   8.109 +	{ 0xf8, 0x28, "SRA %r0"    },
   8.110 +	{ 0xf8, 0x30, "SWAP %r0"   },
   8.111 +	{ 0xf8, 0x38, "SRL %r0"    },
   8.112 +	{ 0xc0, 0x40, "BIT %b,%r0" },
   8.113 +	{ 0xc0, 0x80, "RES %b,%r0" },
   8.114 +	{ 0xc0, 0xc0, "SET %b,%r0" },
   8.115 +	{ 0x00, 0x00, "DB CBh,%B"  }
   8.116 +};
   8.117 +
   8.118 +static char *addHex(char *p, u8 value)
   8.119 +{
   8.120 +	*p++ = hexDigits[value >> 4];
   8.121 +	*p++ = hexDigits[value & 15];
   8.122 +	return p;
   8.123 +}
   8.124 +
   8.125 +static char *addHex16(char *p, u16 value)
   8.126 +{
   8.127 +	p = addHex(p, value>>8);
   8.128 +	return addHex(p, value & 255);
   8.129 +}
   8.130 +
   8.131 +static char *addStr(char *p, char *s)
   8.132 +{
   8.133 +	while (*s)
   8.134 +	{
   8.135 +		*p++ = *s++;
   8.136 +	}
   8.137 +	return p;
   8.138 +}
   8.139 +
   8.140 +int gbDis(char *buffer, u16 address)
   8.141 +{
   8.142 +	char *p     = buffer;
   8.143 +	int   instr = 1;
   8.144 +	u16   addr  = address;
   8.145 +	sprintf(p, "%04x        ", address);
   8.146 +	p += 12;
   8.147 +
   8.148 +	u8 opcode = gbReadMemoryQuick(address);
   8.149 +	address++;
   8.150 +	char *    mnen;
   8.151 +	GBOPCODE *op;
   8.152 +	if (opcode == 0xcb)
   8.153 +	{
   8.154 +		opcode = gbReadMemoryQuick(address);
   8.155 +		address++;
   8.156 +		instr++;
   8.157 +		op = cbOpcodes;
   8.158 +	}
   8.159 +	else
   8.160 +	{
   8.161 +		op = opcodes;
   8.162 +	}
   8.163 +	while (op->value != (opcode & op->mask))
   8.164 +		op++;
   8.165 +	mnen = op->mnen;
   8.166 +
   8.167 +	u8  b0, b1;
   8.168 +	s8  disp;
   8.169 +	int shift;
   8.170 +
   8.171 +	while (*mnen)
   8.172 +	{
   8.173 +		if (*mnen == '%')
   8.174 +		{
   8.175 +			mnen++;
   8.176 +			switch (*mnen++)
   8.177 +			{
   8.178 +			case 'W':
   8.179 +				b0 = gbReadMemoryQuick(address);
   8.180 +				address++;
   8.181 +				b1 = gbReadMemoryQuick(address);
   8.182 +				address++;
   8.183 +				p      = addHex16(p, b0|b1<<8);
   8.184 +				instr += 2;
   8.185 +				*p++   = 'h';
   8.186 +				break;
   8.187 +			case 'B':
   8.188 +				p    = addHex(p, gbReadMemoryQuick(address));
   8.189 +				*p++ = 'h';
   8.190 +				address++;
   8.191 +				instr++;
   8.192 +				break;
   8.193 +			case 'D':
   8.194 +				disp = gbReadMemoryQuick(address);
   8.195 +				if (disp >= 0)
   8.196 +					*p++ = '+';
   8.197 +				p += sprintf(p, "%d", disp);
   8.198 +				instr++;
   8.199 +				break;
   8.200 +			case 'd':
   8.201 +				disp = gbReadMemoryQuick(address);
   8.202 +				address++;
   8.203 +				p    = addHex16(p, address+disp);
   8.204 +				*p++ = 'h';
   8.205 +				instr++;
   8.206 +				break;
   8.207 +			case 'b':
   8.208 +				// kind of a hack, but it works :-)
   8.209 +				*p++ = hexDigits[(opcode >> 3) & 7];
   8.210 +				break;
   8.211 +			case 'r':
   8.212 +				shift = *mnen++ - '0';
   8.213 +				p     = addStr(p, registers[(opcode >> shift) & 7]);
   8.214 +				break;
   8.215 +			case 'R':
   8.216 +				shift = *mnen++ - '0';
   8.217 +				p     = addStr(p, registers16[(opcode >> shift) & 3]);
   8.218 +				break;
   8.219 +			case 't':
   8.220 +				shift = *mnen++ - '0';
   8.221 +				p     = addStr(p, registers16[4+((opcode >> shift) & 3)]);
   8.222 +				break;
   8.223 +			case 'P':
   8.224 +				p = addHex(p, ((opcode >> 3) & 7) * 8);
   8.225 +				break;
   8.226 +			case 'c':
   8.227 +				shift = *mnen++ - '0';
   8.228 +				p     = addStr(p, cond[(opcode >> shift) & 3]);
   8.229 +				break;
   8.230 +			}
   8.231 +		}
   8.232 +		else
   8.233 +			*p++ = *mnen++;
   8.234 +	}
   8.235 +	for (int i = 0; i < instr; i++)
   8.236 +	{
   8.237 +		u16 a = addr + i;
   8.238 +		addHex(buffer+5+i*2, gbReadMemoryQuick(a));
   8.239 +	}
   8.240 +	*p = 0;
   8.241 +	return instr;
   8.242 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/gb/gbGfx.cpp	Sat Mar 03 11:44:47 2012 -0600
     9.3 @@ -0,0 +1,552 @@
     9.4 +#include <cstring>
     9.5 +
     9.6 +#include "gbGlobals.h"
     9.7 +#include "gbSGB.h"
     9.8 +
     9.9 +extern int32 layerSettings;
    9.10 +
    9.11 +u8 gbInvertTab[256] = {
    9.12 +	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    9.13 +	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    9.14 +	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    9.15 +	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    9.16 +	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    9.17 +	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    9.18 +	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    9.19 +	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    9.20 +	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    9.21 +	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    9.22 +	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    9.23 +	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    9.24 +	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    9.25 +	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    9.26 +	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    9.27 +	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    9.28 +	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    9.29 +	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    9.30 +	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    9.31 +	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    9.32 +	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    9.33 +	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    9.34 +	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    9.35 +	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    9.36 +	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    9.37 +	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    9.38 +	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    9.39 +	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    9.40 +	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    9.41 +	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    9.42 +	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    9.43 +	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
    9.44 +};
    9.45 +
    9.46 +u16 gbLineMix[160];
    9.47 +
    9.48 +void gbRenderLine()
    9.49 +{
    9.50 +	u8 *bank0;
    9.51 +	u8 *bank1;
    9.52 +	if (gbCgbMode)
    9.53 +	{
    9.54 +		bank0 = &gbVram[0x0000];
    9.55 +		bank1 = &gbVram[0x2000];
    9.56 +	}
    9.57 +	else
    9.58 +	{
    9.59 +		bank0 = &gbMemory[0x8000];
    9.60 +		bank1 = NULL;
    9.61 +	}
    9.62 +
    9.63 +	int tile_map = 0x1800;
    9.64 +	if ((register_LCDC & 8) != 0)
    9.65 +		tile_map = 0x1c00;
    9.66 +
    9.67 +	int tile_pattern = 0x0800;
    9.68 +
    9.69 +	if ((register_LCDC & 16) != 0)
    9.70 +		tile_pattern = 0x0000;
    9.71 +
    9.72 +	int x = 0;
    9.73 +	int y = register_LY;
    9.74 +
    9.75 +	if (y >= 144)
    9.76 +		return;
    9.77 +
    9.78 +	//  int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip;
    9.79 +
    9.80 +	int sx = register_SCX;
    9.81 +	int sy = register_SCY;
    9.82 +
    9.83 +	sy += y;
    9.84 +
    9.85 +	sy &= 255;
    9.86 +
    9.87 +	int tx = sx >> 3;
    9.88 +	int ty = sy >> 3;
    9.89 +
    9.90 +	int bx = 1 << (7 - (sx & 7));
    9.91 +	int by = sy & 7;
    9.92 +
    9.93 +	int tile_map_line_y = tile_map + ty * 32;
    9.94 +
    9.95 +	int tile_map_address = tile_map_line_y + tx;
    9.96 +
    9.97 +	u8 attrs = 0;
    9.98 +	if (bank1 != NULL)
    9.99 +		attrs = bank1[tile_map_address];
   9.100 +
   9.101 +	u8 tile = bank0[tile_map_address];
   9.102 +
   9.103 +	tile_map_address++;
   9.104 +
   9.105 +	if ((register_LCDC & 16) == 0)
   9.106 +	{
   9.107 +		if (tile < 128)
   9.108 +			tile += 128;
   9.109 +		else
   9.110 +			tile -= 128;
   9.111 +	}
   9.112 +
   9.113 +	int tile_pattern_address = tile_pattern + tile * 16 + by*2;
   9.114 +
   9.115 +	if (register_LCDC & 0x80)
   9.116 +	{
   9.117 +		if ((register_LCDC & 0x01 || gbCgbMode) && (layerSettings & 0x0100))
   9.118 +		{
   9.119 +			while (x < 160)
   9.120 +			{
   9.121 +				u8 tile_a = 0;
   9.122 +				u8 tile_b = 0;
   9.123 +
   9.124 +				if (attrs & 0x40)
   9.125 +				{
   9.126 +					tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2;
   9.127 +				}
   9.128 +
   9.129 +				if (attrs & 0x08)
   9.130 +				{
   9.131 +					tile_a = bank1[tile_pattern_address++];
   9.132 +					tile_b = bank1[tile_pattern_address];
   9.133 +				}
   9.134 +				else
   9.135 +				{
   9.136 +					tile_a = bank0[tile_pattern_address++];
   9.137 +					tile_b = bank0[tile_pattern_address];
   9.138 +				}
   9.139 +
   9.140 +				if (attrs & 0x20)
   9.141 +				{
   9.142 +					tile_a = gbInvertTab[tile_a];
   9.143 +					tile_b = gbInvertTab[tile_b];
   9.144 +				}
   9.145 +
   9.146 +				while (bx > 0)
   9.147 +				{
   9.148 +					u8 c = (tile_a & bx) ? 1 : 0;
   9.149 +					c += ((tile_b & bx) ? 2 : 0);
   9.150 +
   9.151 +					gbLineBuffer[x] = c; // mark the gbLineBuffer color
   9.152 +
   9.153 +					if (attrs & 0x80)
   9.154 +						gbLineBuffer[x] |= 0x300;
   9.155 +
   9.156 +					if (gbCgbMode)
   9.157 +					{
   9.158 +						c = c + (attrs & 7)*4;
   9.159 +					}
   9.160 +					else
   9.161 +					{
   9.162 +						c = gbBgp[c];
   9.163 +						if (gbSgbMode && !gbCgbMode)
   9.164 +						{
   9.165 +							int dx = x >> 3;
   9.166 +							int dy = y >> 3;
   9.167 +
   9.168 +							int palette = gbSgbATF[dy * 20 + dx];
   9.169 +
   9.170 +							if (c == 0)
   9.171 +								palette = 0;
   9.172 +
   9.173 +							c = c + 4*palette;
   9.174 +						}
   9.175 +					}
   9.176 +					gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c]] :
   9.177 +					               gbPalette[c];
   9.178 +					x++;
   9.179 +					if (x >= 160)
   9.180 +						break;
   9.181 +					bx >>= 1;
   9.182 +				}
   9.183 +				tx++;
   9.184 +				if (tx == 32)
   9.185 +					tx = 0;
   9.186 +				bx = 128;
   9.187 +
   9.188 +				if (bank1)
   9.189 +					attrs = bank1[tile_map_line_y + tx];
   9.190 +
   9.191 +				tile = bank0[tile_map_line_y + tx];
   9.192 +
   9.193 +				if ((register_LCDC & 16) == 0)
   9.194 +				{
   9.195 +					if (tile < 128)
   9.196 +						tile += 128;
   9.197 +					else
   9.198 +						tile -= 128;
   9.199 +				}
   9.200 +				tile_pattern_address = tile_pattern + tile * 16 + by * 2;
   9.201 +			}
   9.202 +		}
   9.203 +		else
   9.204 +		{
   9.205 +			for (int i = 0; i < 160; i++)
   9.206 +			{
   9.207 +				gbLineMix[i]    = gbPalette[0];
   9.208 +				gbLineBuffer[i] = 0;
   9.209 +			}
   9.210 +		}
   9.211 +
   9.212 +		// do the window display
   9.213 +		if ((register_LCDC & 0x20) && (layerSettings & 0x2000))
   9.214 +		{
   9.215 +			int wy = register_WY;
   9.216 +
   9.217 +			if (y >= wy)
   9.218 +			{
   9.219 +				int wx = register_WX;
   9.220 +				wx -= 7;
   9.221 +
   9.222 +				if (wx <= 159 && gbWindowLine <= 143)
   9.223 +				{
   9.224 +					tile_map = 0x1800;
   9.225 +
   9.226 +					if ((register_LCDC & 0x40) != 0)
   9.227 +						tile_map = 0x1c00;
   9.228 +
   9.229 +					if (gbWindowLine == -1)
   9.230 +					{
   9.231 +						gbWindowLine = 0;
   9.232 +					}
   9.233 +
   9.234 +					tx = 0;
   9.235 +					ty = gbWindowLine >> 3;
   9.236 +
   9.237 +					bx = 128;
   9.238 +					by = gbWindowLine & 7;
   9.239 +
   9.240 +					if (wx < 0)
   9.241 +					{
   9.242 +						bx >>= (-wx);
   9.243 +						wx   = 0;
   9.244 +					}
   9.245 +
   9.246 +					tile_map_line_y = tile_map + ty * 32;
   9.247 +
   9.248 +					tile_map_address = tile_map_line_y + tx;
   9.249 +
   9.250 +					x = wx;
   9.251 +
   9.252 +					tile = bank0[tile_map_address];
   9.253 +					u8 attrs = 0;
   9.254 +					if (bank1)
   9.255 +						attrs = bank1[tile_map_address];
   9.256 +					tile_map_address++;
   9.257 +
   9.258 +					if ((register_LCDC & 16) == 0)
   9.259 +					{
   9.260 +						if (tile < 128)
   9.261 +							tile += 128;
   9.262 +						else
   9.263 +							tile -= 128;
   9.264 +					}
   9.265 +
   9.266 +					tile_pattern_address = tile_pattern + tile * 16 + by*2;
   9.267 +
   9.268 +					while (x < 160)
   9.269 +					{
   9.270 +						u8 tile_a = 0;
   9.271 +						u8 tile_b = 0;
   9.272 +
   9.273 +						if (attrs & 0x40)
   9.274 +						{
   9.275 +							tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2;
   9.276 +						}
   9.277 +
   9.278 +						if (attrs & 0x08)
   9.279 +						{
   9.280 +							tile_a = bank1[tile_pattern_address++];
   9.281 +							tile_b = bank1[tile_pattern_address];
   9.282 +						}
   9.283 +						else
   9.284 +						{
   9.285 +							tile_a = bank0[tile_pattern_address++];
   9.286 +							tile_b = bank0[tile_pattern_address];
   9.287 +						}
   9.288 +
   9.289 +						if (attrs & 0x20)
   9.290 +						{
   9.291 +							tile_a = gbInvertTab[tile_a];
   9.292 +							tile_b = gbInvertTab[tile_b];
   9.293 +						}
   9.294 +
   9.295 +						while (bx > 0)
   9.296 +						{
   9.297 +							u8 c = (tile_a & bx) != 0 ? 1 : 0;
   9.298 +							c += ((tile_b & bx) != 0 ? 2 : 0);
   9.299 +
   9.300 +							if (attrs & 0x80)
   9.301 +								gbLineBuffer[x] = 0x300 + c;
   9.302 +							else
   9.303 +								gbLineBuffer[x] = 0x100 + c;
   9.304 +
   9.305 +							if (gbCgbMode)
   9.306 +							{
   9.307 +								c = c + (attrs & 7) * 4;
   9.308 +							}
   9.309 +							else
   9.310 +							{
   9.311 +								c = gbBgp[c];
   9.312 +								if (gbSgbMode && !gbCgbMode)
   9.313 +								{
   9.314 +									int dx = x >> 3;
   9.315 +									int dy = y >> 3;
   9.316 +
   9.317 +									int palette = gbSgbATF[dy * 20 + dx];
   9.318 +
   9.319 +									if (c == 0)
   9.320 +										palette = 0;
   9.321 +
   9.322 +									c = c + 4*palette;
   9.323 +								}
   9.324 +							}
   9.325 +							gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c]] :
   9.326 +							               gbPalette[c];
   9.327 +							x++;
   9.328 +							if (x >= 160)
   9.329 +								break;
   9.330 +							bx >>= 1;
   9.331 +						}
   9.332 +						tx++;
   9.333 +						if (tx == 32)
   9.334 +							tx = 0;
   9.335 +						bx   = 128;
   9.336 +						tile = bank0[tile_map_line_y + tx];
   9.337 +						if (bank1)
   9.338 +							attrs = bank1[tile_map_line_y + tx];
   9.339 +
   9.340 +						if ((register_LCDC & 16) == 0)
   9.341 +						{
   9.342 +							if (tile < 128)
   9.343 +								tile += 128;
   9.344 +							else
   9.345 +								tile -= 128;
   9.346 +						}
   9.347 +						tile_pattern_address = tile_pattern + tile * 16 + by * 2;
   9.348 +					}
   9.349 +					gbWindowLine++;
   9.350 +				}
   9.351 +			}
   9.352 +		}
   9.353 +	}
   9.354 +	else
   9.355 +	{
   9.356 +		for (int i = 0; i < 160; i++)
   9.357 +		{
   9.358 +			gbLineMix[i]    = gbPalette[0];
   9.359 +			gbLineBuffer[i] = 0;
   9.360 +		}
   9.361 +	}
   9.362 +}
   9.363 +
   9.364 +void gbDrawSpriteTile(int tile, int x, int y, int t, int flags,
   9.365 +                      int size, int spriteNumber)
   9.366 +{
   9.367 +	u8 *bank0;
   9.368 +	u8 *bank1;
   9.369 +	if (gbCgbMode)
   9.370 +	{
   9.371 +		if (register_VBK & 1)
   9.372 +		{
   9.373 +			bank0 = &gbVram[0x0000];
   9.374 +			bank1 = &gbVram[0x2000];
   9.375 +		}
   9.376 +		else
   9.377 +		{
   9.378 +			bank0 = &gbVram[0x0000];
   9.379 +			bank1 = &gbVram[0x2000];
   9.380 +		}
   9.381 +	}
   9.382 +	else
   9.383 +	{
   9.384 +		bank0 = &gbMemory[0x8000];
   9.385 +		bank1 = NULL;
   9.386 +	}
   9.387 +
   9.388 +	int init = 0x0000;
   9.389 +
   9.390 +	//  int yLine = (y+gbBorderRowSkip) * gbBorderLineSkip;
   9.391 +
   9.392 +	u8 *pal = gbObp0;
   9.393 +
   9.394 +	int flipx = (flags & 0x20);
   9.395 +	int flipy = (flags & 0x40);
   9.396 +
   9.397 +	if ((flags & 0x10))
   9.398 +		pal = gbObp1;
   9.399 +
   9.400 +	if (flipy)
   9.401 +	{
   9.402 +		t = (size ? 15 : 7) - t;
   9.403 +	}
   9.404 +
   9.405 +	int prio =  flags & 0x80;
   9.406 +
   9.407 +	int address = init + tile * 16 + 2*t;
   9.408 +	int a       = 0;
   9.409 +	int b       = 0;
   9.410 +
   9.411 +	if (gbCgbMode && flags & 0x08)
   9.412 +	{
   9.413 +		a = bank1[address++];
   9.414 +		b = bank1[address++];
   9.415 +	}
   9.416 +	else
   9.417 +	{
   9.418 +		a = bank0[address++];
   9.419 +		b = bank0[address++];
   9.420 +	}
   9.421 +
   9.422 +	for (int xx = 0; xx < 8; xx++)
   9.423 +	{
   9.424 +		u8 mask = 1 << (7-xx);
   9.425 +		u8 c    = 0;
   9.426 +		if ((a & mask))
   9.427 +			c++;
   9.428 +		if ((b & mask))
   9.429 +			c += 2;
   9.430 +
   9.431 +		if (c == 0)
   9.432 +			continue;
   9.433 +
   9.434 +		int xxx = xx+x;
   9.435 +		if (flipx)
   9.436 +			xxx = (7-xx+x);
   9.437 +
   9.438 +		if (xxx < 0 || xxx > 159)
   9.439 +			continue;
   9.440 +
   9.441 +		u16 color = gbLineBuffer[xxx];
   9.442 +
   9.443 +		if (prio)
   9.444 +		{
   9.445 +			if (color < 0x200 && ((color & 0xFF) != 0))
   9.446 +				continue;
   9.447 +		}
   9.448 +		if (color >= 0x300 && color != 0x300)
   9.449 +			continue;
   9.450 +		else if (color >= 0x200 && color < 0x300)
   9.451 +		{
   9.452 +			int sprite = color & 0xff;
   9.453 +
   9.454 +			int spriteX = gbMemory[0xfe00 + 4 * sprite + 1] - 8;
   9.455 +
   9.456 +			if (spriteX == x)
   9.457 +			{
   9.458 +				if (sprite < spriteNumber)
   9.459 +					continue;
   9.460 +			}
   9.461 +			else
   9.462 +			{
   9.463 +				if (gbCgbMode)
   9.464 +				{
   9.465 +					if (sprite < spriteNumber)
   9.466 +						continue;
   9.467 +				}
   9.468 +				else
   9.469 +				{
   9.470 +					if (spriteX < x+8)
   9.471 +						continue;
   9.472 +				}
   9.473 +			}
   9.474 +		}
   9.475 +
   9.476 +		gbLineBuffer[xxx] = 0x200 + spriteNumber;
   9.477 +
   9.478 +		// make sure that sprites will work even in CGB mode
   9.479 +		if (gbCgbMode)
   9.480 +		{
   9.481 +			c = c + (flags & 0x07)*4 + 32;
   9.482 +		}
   9.483 +		else
   9.484 +		{
   9.485 +			c = pal[c];
   9.486 +
   9.487 +			if (gbSgbMode && !gbCgbMode)
   9.488 +			{
   9.489 +				int dx = xxx >> 3;
   9.490 +				int dy = y >> 3;
   9.491 +
   9.492 +				int palette = gbSgbATF[dy * 20 + dx];
   9.493 +
   9.494 +				if (c == 0)
   9.495 +					palette = 0;
   9.496 +
   9.497 +				c = c + 4*palette;
   9.498 +			}
   9.499 +			else
   9.500 +			{
   9.501 +				c += 4;
   9.502 +			}
   9.503 +		}
   9.504 +
   9.505 +		gbLineMix[xxx] = gbColorOption ? gbColorFilter[gbPalette[c]] :
   9.506 +		                 gbPalette[c];
   9.507 +	}
   9.508 +}
   9.509 +
   9.510 +void gbDrawSprites()
   9.511 +{
   9.512 +	int x     = 0;
   9.513 +	int y     = 0;
   9.514 +	int count = 0;
   9.515 +
   9.516 +	int size = (register_LCDC & 4);
   9.517 +
   9.518 +	if (!(register_LCDC & 0x80))
   9.519 +		return;
   9.520 +
   9.521 +	if ((register_LCDC & 2) && (layerSettings & 0x1000))
   9.522 +	{
   9.523 +		int yc = register_LY;
   9.524 +
   9.525 +		int address = 0xfe00;
   9.526 +		for (int i = 0; i < 40; i++)
   9.527 +		{
   9.528 +			y = gbMemory[address++];
   9.529 +			x = gbMemory[address++];
   9.530 +			int tile = gbMemory[address++];
   9.531 +			if (size)
   9.532 +				tile &= 254;
   9.533 +			int flags = gbMemory[address++];
   9.534 +
   9.535 +			if (x > 0 && y > 0 && x < 168 && y < 160)
   9.536 +			{
   9.537 +				// check if sprite intersects current line
   9.538 +				int t = yc -y + 16;
   9.539 +				if (size && t >= 0 && t < 16)
   9.540 +				{
   9.541 +					gbDrawSpriteTile(tile, x-8, yc, t, flags, size, i);
   9.542 +					count++;
   9.543 +				}
   9.544 +				else if (!size && t >= 0 && t < 8)
   9.545 +				{
   9.546 +					gbDrawSpriteTile(tile, x-8, yc, t, flags, size, i);
   9.547 +					count++;
   9.548 +				}
   9.549 +			}
   9.550 +			// sprite limit reached!
   9.551 +			if (count >= 10)
   9.552 +				break;
   9.553 +		}
   9.554 +	}
   9.555 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/gb/gbGlobals.cpp	Sat Mar 03 11:44:47 2012 -0600
    10.3 @@ -0,0 +1,39 @@
    10.4 +#include "../Port.h"
    10.5 +#include "GB.h"
    10.6 +
    10.7 +u8 *gbMemoryMap[16];
    10.8 +
    10.9 +int32 gbRomSizeMask = 0;
   10.10 +int32 gbRomSize     = 0;
   10.11 +int32 gbRamSizeMask = 0;
   10.12 +int32 gbRamSize     = 0;
   10.13 +
   10.14 +u8 * gbMemory     = NULL;
   10.15 +u8 * gbVram       = NULL;
   10.16 +u8 * gbRom        = NULL;
   10.17 +u8 * gbRam        = NULL;
   10.18 +u8 * gbWram       = NULL;
   10.19 +u16 *gbLineBuffer = NULL;
   10.20 +
   10.21 +u16   gbPalette[128];
   10.22 +u8    gbBgp[4] = { 0, 1, 2, 3};
   10.23 +u8    gbObp0[4] = { 0, 1, 2, 3};
   10.24 +u8    gbObp1[4] = { 0, 1, 2, 3};
   10.25 +int32 gbWindowLine = -1;
   10.26 +
   10.27 +int32 gbCgbMode = 0;
   10.28 +
   10.29 +u16   gbColorFilter[32768];
   10.30 +int32 gbColorOption      = 0;
   10.31 +int32 gbPaletteOption    = 0;
   10.32 +int32 gbEmulatorType     = 0;
   10.33 +int32 gbBorderOn         = 1;
   10.34 +int32 gbBorderAutomatic  = 0;
   10.35 +int32 gbBorderLineSkip   = 160;
   10.36 +int32 gbBorderRowSkip    = 0;
   10.37 +int32 gbBorderColumnSkip = 0;
   10.38 +int32 gbDmaTicks         = 0;
   10.39 +bool8 gbNullInputHackEnabled	 = false;
   10.40 +bool8 gbNullInputHackTempEnabled = false;
   10.41 +
   10.42 +u8 (*gbSerialFunction)(u8) = NULL;
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/gb/gbGlobals.h	Sat Mar 03 11:44:47 2012 -0600
    11.3 @@ -0,0 +1,95 @@
    11.4 +#ifndef VBA_GB_GLOBALS_H
    11.5 +#define VBA_GB_GLOBALS_H
    11.6 +
    11.7 +#if _MSC_VER > 1000
    11.8 +#pragma once
    11.9 +#endif // _MSC_VER > 1000
   11.10 +
   11.11 +#include "../Port.h"
   11.12 +
   11.13 +extern int32 gbRomSizeMask;
   11.14 +extern int32 gbRomSize;
   11.15 +extern int32 gbRamSize;
   11.16 +extern int32 gbRamSizeMask;
   11.17 +
   11.18 +extern u8 * gbRom;
   11.19 +extern u8 * gbRam;
   11.20 +extern u8 * gbVram;
   11.21 +extern u8 * gbWram;
   11.22 +extern u8 * gbMemory;
   11.23 +extern u16 *gbLineBuffer;
   11.24 +
   11.25 +extern u8 *gbMemoryMap[16];
   11.26 +
   11.27 +inline u8 gbReadMemoryQuick(u16 address)
   11.28 +{
   11.29 +	extern int32 gbEchoRAMFixOn;
   11.30 +	if (gbEchoRAMFixOn)
   11.31 +	{
   11.32 +		if (address >= 0xe000 && address < 0xfe00)
   11.33 +		{
   11.34 +			address -= 0x2000;
   11.35 +		}
   11.36 +	}
   11.37 +	return gbMemoryMap[address>>12][address&0xfff];
   11.38 +}
   11.39 +
   11.40 +inline void gbWriteMemoryQuick(u16 address, u8 value)
   11.41 +{
   11.42 +	extern int32 gbEchoRAMFixOn;
   11.43 +	if (gbEchoRAMFixOn)
   11.44 +	{
   11.45 +		if (address >= 0xe000 && address < 0xfe00)
   11.46 +		{
   11.47 +			address -= 0x2000;
   11.48 +		}
   11.49 +	}
   11.50 +	gbMemoryMap[address>>12][address&0xfff] = value;
   11.51 +}
   11.52 +
   11.53 +inline u8 gbReadROMQuick(u32 address)
   11.54 +{
   11.55 +	return gbRom[address];
   11.56 +}
   11.57 +
   11.58 +extern int32 gbFrameSkip;
   11.59 +extern u16   gbColorFilter[32768];
   11.60 +extern int32 gbColorOption;
   11.61 +extern int32 gbPaletteOption;
   11.62 +extern int32 gbEmulatorType;
   11.63 +extern int32 gbBorderOn;
   11.64 +extern int32 gbBorderAutomatic;
   11.65 +extern int32 gbCgbMode;
   11.66 +extern int32 gbSgbMode;
   11.67 +extern int32 gbWindowLine;
   11.68 +extern int32 gbSpeed;
   11.69 +extern u8    gbBgp[4];
   11.70 +extern u8    gbObp0[4];
   11.71 +extern u8    gbObp1[4];
   11.72 +extern u16   gbPalette[128];
   11.73 +
   11.74 +extern u8 register_LCDC;
   11.75 +extern u8 register_LY;
   11.76 +extern u8 register_SCY;
   11.77 +extern u8 register_SCX;
   11.78 +extern u8 register_WY;
   11.79 +extern u8 register_WX;
   11.80 +extern u8 register_VBK;
   11.81 +
   11.82 +extern int emulating;
   11.83 +
   11.84 +extern int32 gbBorderLineSkip;
   11.85 +extern int32 gbBorderRowSkip;
   11.86 +extern int32 gbBorderColumnSkip;
   11.87 +extern int32 gbDmaTicks;
   11.88 +
   11.89 +extern bool8 useOldFrameTiming;
   11.90 +extern bool8 gbNullInputHackEnabled;
   11.91 +extern bool8 gbNullInputHackTempEnabled;
   11.92 +
   11.93 +extern void gbRenderLine();
   11.94 +extern void gbDrawSprites();
   11.95 +
   11.96 +extern u8 (*gbSerialFunction)(u8);
   11.97 +
   11.98 +#endif // VBA_GB_GLOBALS_H
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/gb/gbMemory.cpp	Sat Mar 03 11:44:47 2012 -0600
    12.3 @@ -0,0 +1,1070 @@
    12.4 +#include "gbGlobals.h"
    12.5 +#include "gbMemory.h"
    12.6 +#include "../common/System.h"
    12.7 +#include "../common/movie.h"
    12.8 +
    12.9 +mapperMBC1 gbDataMBC1 = {
   12.10 +	0, // RAM enable
   12.11 +	1, // ROM bank
   12.12 +	0, // RAM bank
   12.13 +	0, // memory model
   12.14 +	0, // ROM high address
   12.15 +	0 // RAM address
   12.16 +};
   12.17 +
   12.18 +// MBC1 ROM write registers
   12.19 +void mapperMBC1ROM(u16 address, u8 value)
   12.20 +{
   12.21 +	int tmpAddress = 0;
   12.22 +
   12.23 +	switch (address & 0x6000)
   12.24 +	{
   12.25 +	case 0x0000: // RAM enable register
   12.26 +		gbDataMBC1.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0);
   12.27 +		break;
   12.28 +	case 0x2000: // ROM bank select
   12.29 +		//    value = value & 0x1f;
   12.30 +		if (value == 0)
   12.31 +			value = 1;
   12.32 +		if (value == gbDataMBC1.mapperROMBank)
   12.33 +			break;
   12.34 +
   12.35 +		tmpAddress = value << 14;
   12.36 +
   12.37 +		// check current model
   12.38 +		if (gbDataMBC1.mapperMemoryModel == 0)
   12.39 +		{
   12.40 +			// model is 16/8, so we have a high address in use
   12.41 +			tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19;
   12.42 +		}
   12.43 +
   12.44 +		tmpAddress &= gbRomSizeMask;
   12.45 +		gbDataMBC1.mapperROMBank = value;
   12.46 +		gbMemoryMap[0x04]        = &gbRom[tmpAddress];
   12.47 +		gbMemoryMap[0x05]        = &gbRom[tmpAddress + 0x1000];
   12.48 +		gbMemoryMap[0x06]        = &gbRom[tmpAddress + 0x2000];
   12.49 +		gbMemoryMap[0x07]        = &gbRom[tmpAddress + 0x3000];
   12.50 +		break;
   12.51 +	case 0x4000: // RAM bank select
   12.52 +		if (gbDataMBC1.mapperMemoryModel == 1)
   12.53 +		{
   12.54 +			// 4/32 model, RAM bank switching provided
   12.55 +			value = value & 0x03;
   12.56 +			if (value == gbDataMBC1.mapperRAMBank)
   12.57 +				break;
   12.58 +			tmpAddress                  = value << 13;
   12.59 +			tmpAddress                 &= gbRamSizeMask;
   12.60 +			gbMemoryMap[0x0a]           = &gbRam[tmpAddress];
   12.61 +			gbMemoryMap[0x0b]           = &gbRam[tmpAddress + 0x1000];
   12.62 +			gbDataMBC1.mapperRAMBank    = value;
   12.63 +			gbDataMBC1.mapperRAMAddress = tmpAddress;
   12.64 +		}
   12.65 +		else
   12.66 +		{
   12.67 +			// 16/8, set the high address
   12.68 +			gbDataMBC1.mapperROMHighAddress = value & 0x03;
   12.69 +			tmpAddress        = gbDataMBC1.mapperROMBank << 14;
   12.70 +			tmpAddress       |= (gbDataMBC1.mapperROMHighAddress) << 19;
   12.71 +			tmpAddress       &= gbRomSizeMask;
   12.72 +			gbMemoryMap[0x04] = &gbRom[tmpAddress];
   12.73 +			gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
   12.74 +			gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
   12.75 +			gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
   12.76 +		}
   12.77 +		break;
   12.78 +	case 0x6000: // memory model select
   12.79 +		gbDataMBC1.mapperMemoryModel = value & 1;
   12.80 +		break;
   12.81 +	}
   12.82 +}
   12.83 +
   12.84 +// MBC1 RAM write
   12.85 +void mapperMBC1RAM(u16 address, u8 value)
   12.86 +{
   12.87 +	if (gbDataMBC1.mapperRAMEnable)
   12.88 +	{
   12.89 +		if (gbRamSize)
   12.90 +		{
   12.91 +			gbWriteMemoryQuick(address, value);
   12.92 +			systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
   12.93 +		}
   12.94 +	}
   12.95 +}
   12.96 +
   12.97 +void memoryUpdateMapMBC1()
   12.98 +{
   12.99 +	int tmpAddress = gbDataMBC1.mapperROMBank << 14;
  12.100 +
  12.101 +	// check current model
  12.102 +	if (gbDataMBC1.mapperMemoryModel == 1)
  12.103 +	{
  12.104 +		// model is 16/8, so we have a high address in use
  12.105 +		tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19;
  12.106 +	}
  12.107 +
  12.108 +	tmpAddress       &= gbRomSizeMask;
  12.109 +	gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.110 +	gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.111 +	gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.112 +	gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.113 +
  12.114 +	if (gbRamSize)
  12.115 +	{
  12.116 +		gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress];
  12.117 +		gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000];
  12.118 +	}
  12.119 +}
  12.120 +
  12.121 +mapperMBC2 gbDataMBC2 = {
  12.122 +	0, // RAM enable
  12.123 +	1 // ROM bank
  12.124 +};
  12.125 +
  12.126 +// MBC2 ROM write registers
  12.127 +void mapperMBC2ROM(u16 address, u8 value)
  12.128 +{
  12.129 +	switch (address & 0x6000)
  12.130 +	{
  12.131 +	case 0x0000: // RAM enable
  12.132 +		if (!(address & 0x0100))
  12.133 +		{
  12.134 +			gbDataMBC2.mapperRAMEnable = (value & 0x0f) == 0x0a;
  12.135 +		}
  12.136 +		break;
  12.137 +	case 0x2000: // ROM bank select
  12.138 +		if (address & 0x0100)
  12.139 +		{
  12.140 +			value &= 0x0f;
  12.141 +
  12.142 +			if (value == 0)
  12.143 +				value = 1;
  12.144 +			if (gbDataMBC2.mapperROMBank != value)
  12.145 +			{
  12.146 +				gbDataMBC2.mapperROMBank = value;
  12.147 +
  12.148 +				int tmpAddress = value << 14;
  12.149 +
  12.150 +				tmpAddress &= gbRomSizeMask;
  12.151 +
  12.152 +				gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.153 +				gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.154 +				gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.155 +				gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.156 +			}
  12.157 +		}
  12.158 +		break;
  12.159 +	}
  12.160 +}
  12.161 +
  12.162 +// MBC2 RAM write
  12.163 +void mapperMBC2RAM(u16 address, u8 value)
  12.164 +{
  12.165 +	if (gbDataMBC2.mapperRAMEnable)
  12.166 +	{
  12.167 +		if (gbRamSize && address < 0xa200)
  12.168 +		{
  12.169 +			gbWriteMemoryQuick(address, value);
  12.170 +			systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  12.171 +		}
  12.172 +	}
  12.173 +}
  12.174 +
  12.175 +void memoryUpdateMapMBC2()
  12.176 +{
  12.177 +	int tmpAddress = gbDataMBC2.mapperROMBank << 14;
  12.178 +
  12.179 +	tmpAddress &= gbRomSizeMask;
  12.180 +
  12.181 +	gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.182 +	gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.183 +	gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.184 +	gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.185 +}
  12.186 +
  12.187 +mapperMBC3 gbDataMBC3 = {
  12.188 +	0, // RAM enable
  12.189 +	1, // ROM bank
  12.190 +	0, // RAM bank
  12.191 +	0, // RAM address
  12.192 +	0, // timer clock latch
  12.193 +	0, // timer clock register
  12.194 +	0, // timer seconds
  12.195 +	0, // timer minutes
  12.196 +	0, // timer hours
  12.197 +	0, // timer days
  12.198 +	0, // timer control
  12.199 +	0, // timer latched seconds
  12.200 +	0, // timer latched minutes
  12.201 +	0, // timer latched hours
  12.202 +	0, // timer latched days
  12.203 +	0, // timer latched control
  12.204 +	(time_t)-1 // last time
  12.205 +};
  12.206 +
  12.207 +void memoryUpdateMBC3Clock()
  12.208 +{
  12.209 +	time_t now;
  12.210 +
  12.211 +	if (VBAMovieActive() || VBAMovieLoading())
  12.212 +		now = (time_t)(VBAMovieGetId() + VBAMovieGetFrameCounter()/60); /// FIXME: is /60 the right factor?
  12.213 +	else
  12.214 +		now = time(NULL);
  12.215 +
  12.216 +	time_t diff = now - gbDataMBC3.mapperLastTime;
  12.217 +	if (diff > 0)
  12.218 +	{
  12.219 +		// update the clock according to the last update time
  12.220 +		gbDataMBC3.mapperSeconds += (int)(diff % 60);
  12.221 +		if (gbDataMBC3.mapperSeconds > 59)
  12.222 +		{
  12.223 +			gbDataMBC3.mapperSeconds -= 60;
  12.224 +			gbDataMBC3.mapperMinutes++;
  12.225 +		}
  12.226 +
  12.227 +		diff /= 60;
  12.228 +
  12.229 +		gbDataMBC3.mapperMinutes += (int)(diff % 60);
  12.230 +		if (gbDataMBC3.mapperMinutes > 60)
  12.231 +		{
  12.232 +			gbDataMBC3.mapperMinutes -= 60;
  12.233 +			gbDataMBC3.mapperHours++;
  12.234 +		}
  12.235 +
  12.236 +		diff /= 60;
  12.237 +
  12.238 +		gbDataMBC3.mapperHours += (int)(diff % 24);
  12.239 +		if (gbDataMBC3.mapperHours > 24)
  12.240 +		{
  12.241 +			gbDataMBC3.mapperHours -= 24;
  12.242 +			gbDataMBC3.mapperDays++;
  12.243 +		}
  12.244 +		diff /= 24;
  12.245 +
  12.246 +		gbDataMBC3.mapperDays += (int)diff;
  12.247 +		if (gbDataMBC3.mapperDays > 255)
  12.248 +		{
  12.249 +			if (gbDataMBC3.mapperDays > 511)
  12.250 +			{
  12.251 +				gbDataMBC3.mapperDays    %= 512;
  12.252 +				gbDataMBC3.mapperControl |= 0x80;
  12.253 +			}
  12.254 +			gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) |
  12.255 +			                           (gbDataMBC3.mapperDays > 255 ? 1 : 0);
  12.256 +		}
  12.257 +	}
  12.258 +	gbDataMBC3.mapperLastTime = now;
  12.259 +}
  12.260 +
  12.261 +// MBC3 ROM write registers
  12.262 +void mapperMBC3ROM(u16 address, u8 value)
  12.263 +{
  12.264 +	int tmpAddress = 0;
  12.265 +
  12.266 +	switch (address & 0x6000)
  12.267 +	{
  12.268 +	case 0x0000: // RAM enable register
  12.269 +		gbDataMBC3.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0);
  12.270 +		break;
  12.271 +	case 0x2000: // ROM bank select
  12.272 +		value = value & 0x7f;
  12.273 +		if (value == 0)
  12.274 +			value = 1;
  12.275 +		if (value == gbDataMBC3.mapperROMBank)
  12.276 +			break;
  12.277 +
  12.278 +		tmpAddress = value << 14;
  12.279 +
  12.280 +		tmpAddress &= gbRomSizeMask;
  12.281 +		gbDataMBC3.mapperROMBank = value;
  12.282 +		gbMemoryMap[0x04]        = &gbRom[tmpAddress];
  12.283 +		gbMemoryMap[0x05]        = &gbRom[tmpAddress + 0x1000];
  12.284 +		gbMemoryMap[0x06]        = &gbRom[tmpAddress + 0x2000];
  12.285 +		gbMemoryMap[0x07]        = &gbRom[tmpAddress + 0x3000];
  12.286 +
  12.287 +		break;
  12.288 +	case 0x4000: // RAM bank select
  12.289 +		if (value < 8)
  12.290 +		{
  12.291 +			if (value == gbDataMBC3.mapperRAMBank)
  12.292 +				break;
  12.293 +			tmpAddress                  = value << 13;
  12.294 +			tmpAddress                 &= gbRamSizeMask;
  12.295 +			gbMemoryMap[0x0a]           = &gbRam[tmpAddress];
  12.296 +			gbMemoryMap[0x0b]           = &gbRam[tmpAddress + 0x1000];
  12.297 +			gbDataMBC3.mapperRAMBank    = value;
  12.298 +			gbDataMBC3.mapperRAMAddress = tmpAddress;
  12.299 +		}
  12.300 +		else
  12.301 +		{
  12.302 +			if (gbDataMBC3.mapperRAMEnable)
  12.303 +			{
  12.304 +				gbDataMBC3.mapperRAMBank = -1;
  12.305 +
  12.306 +				gbDataMBC3.mapperClockRegister = value;
  12.307 +			}
  12.308 +		}
  12.309 +		break;
  12.310 +	case 0x6000: // clock latch
  12.311 +		if (gbDataMBC3.mapperClockLatch == 0 && value == 1)
  12.312 +		{
  12.313 +			memoryUpdateMBC3Clock();
  12.314 +			gbDataMBC3.mapperLSeconds = gbDataMBC3.mapperSeconds;
  12.315 +			gbDataMBC3.mapperLMinutes = gbDataMBC3.mapperMinutes;
  12.316 +			gbDataMBC3.mapperLHours   = gbDataMBC3.mapperHours;
  12.317 +			gbDataMBC3.mapperLDays    = gbDataMBC3.mapperDays;
  12.318 +			gbDataMBC3.mapperLControl = gbDataMBC3.mapperControl;
  12.319 +		}
  12.320 +		if (value == 0x00 || value == 0x01)
  12.321 +			gbDataMBC3.mapperClockLatch = value;
  12.322 +		break;
  12.323 +	}
  12.324 +}
  12.325 +
  12.326 +// MBC3 RAM write
  12.327 +void mapperMBC3RAM(u16 address, u8 value)
  12.328 +{
  12.329 +	if (gbDataMBC3.mapperRAMEnable)
  12.330 +	{
  12.331 +		if (gbDataMBC3.mapperRAMBank != -1)
  12.332 +		{
  12.333 +			if (gbRamSize)
  12.334 +			{
  12.335 +				gbWriteMemoryQuick(address, value);
  12.336 +				systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  12.337 +			}
  12.338 +		}
  12.339 +		else
  12.340 +		{
  12.341 +			time_t tmp; //Small kludge to get it working on some 64 bit systems.
  12.342 +			if (VBAMovieActive() || VBAMovieLoading())
  12.343 +				gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter()/60;
  12.344 +			else {
  12.345 +				time(&tmp);
  12.346 +				gbDataMBC3.mapperLastTime=(u32)tmp;
  12.347 +			}
  12.348 +			systemScreenMessage(ctime(&tmp), 4);
  12.349 +			gbDataMBC3.mapperLastTime=(u32)tmp;
  12.350 +
  12.351 +			switch (gbDataMBC3.mapperClockRegister)
  12.352 +			{
  12.353 +			case 0x08:
  12.354 +				gbDataMBC3.mapperSeconds = value;
  12.355 +				break;
  12.356 +			case 0x09:
  12.357 +				gbDataMBC3.mapperMinutes = value;
  12.358 +				break;
  12.359 +			case 0x0a:
  12.360 +				gbDataMBC3.mapperHours = value;
  12.361 +				break;
  12.362 +			case 0x0b:
  12.363 +				gbDataMBC3.mapperDays = value;
  12.364 +				break;
  12.365 +			case 0x0c:
  12.366 +				if (gbDataMBC3.mapperControl & 0x80)
  12.367 +					gbDataMBC3.mapperControl = 0x80 | value;
  12.368 +				else
  12.369 +					gbDataMBC3.mapperControl = value;
  12.370 +				break;
  12.371 +			}
  12.372 +		}
  12.373 +	}
  12.374 +}
  12.375 +
  12.376 +// MBC3 read RAM
  12.377 +u8 mapperMBC3ReadRAM(u16 address)
  12.378 +{
  12.379 +	if (gbDataMBC3.mapperRAMEnable)
  12.380 +	{
  12.381 +		if (gbDataMBC3.mapperRAMBank != -1)
  12.382 +		{
  12.383 +			return gbReadMemoryQuick(address);
  12.384 +		}
  12.385 +
  12.386 +		switch (gbDataMBC3.mapperClockRegister)
  12.387 +		{
  12.388 +		case 0x08:
  12.389 +			return gbDataMBC3.mapperLSeconds;
  12.390 +			break;
  12.391 +		case 0x09:
  12.392 +			return gbDataMBC3.mapperLMinutes;
  12.393 +			break;
  12.394 +		case 0x0a:
  12.395 +			return gbDataMBC3.mapperLHours;
  12.396 +			break;
  12.397 +		case 0x0b:
  12.398 +			return gbDataMBC3.mapperLDays;
  12.399 +			break;
  12.400 +		case 0x0c:
  12.401 +			return gbDataMBC3.mapperLControl;
  12.402 +		}
  12.403 +	}
  12.404 +	return 0;
  12.405 +}
  12.406 +
  12.407 +void memoryUpdateMapMBC3()
  12.408 +{
  12.409 +	int tmpAddress = gbDataMBC3.mapperROMBank << 14;
  12.410 +
  12.411 +	tmpAddress &= gbRomSizeMask;
  12.412 +
  12.413 +	gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.414 +	gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.415 +	gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.416 +	gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.417 +
  12.418 +	if (gbDataMBC3.mapperRAMBank >= 0 && gbRamSize)
  12.419 +	{
  12.420 +		tmpAddress        = gbDataMBC3.mapperRAMBank << 13;
  12.421 +		tmpAddress       &= gbRamSizeMask;
  12.422 +		gbMemoryMap[0x0a] = &gbRam[tmpAddress];
  12.423 +		gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000];
  12.424 +	}
  12.425 +}
  12.426 +
  12.427 +mapperMBC5 gbDataMBC5 = {
  12.428 +	0, // RAM enable
  12.429 +	1, // ROM bank
  12.430 +	0, // RAM bank
  12.431 +	0, // ROM high address
  12.432 +	0, // RAM address
  12.433 +	0 // is rumble cartridge?
  12.434 +};
  12.435 +
  12.436 +// MBC5 ROM write registers
  12.437 +void mapperMBC5ROM(u16 address, u8 value)
  12.438 +{
  12.439 +	int tmpAddress = 0;
  12.440 +
  12.441 +	switch (address & 0x6000)
  12.442 +	{
  12.443 +	case 0x0000: // RAM enable register
  12.444 +		gbDataMBC5.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0);
  12.445 +		break;
  12.446 +	case 0x2000: // ROM bank select
  12.447 +		if (address < 0x3000)
  12.448 +		{
  12.449 +			value = value & 0xff;
  12.450 +			if (value == gbDataMBC5.mapperROMBank)
  12.451 +				break;
  12.452 +
  12.453 +			tmpAddress = (value << 14) | (gbDataMBC5.mapperROMHighAddress << 22) ;
  12.454 +
  12.455 +			tmpAddress &= gbRomSizeMask;
  12.456 +			gbDataMBC5.mapperROMBank = value;
  12.457 +			gbMemoryMap[0x04]        = &gbRom[tmpAddress];
  12.458 +			gbMemoryMap[0x05]        = &gbRom[tmpAddress + 0x1000];
  12.459 +			gbMemoryMap[0x06]        = &gbRom[tmpAddress + 0x2000];
  12.460 +			gbMemoryMap[0x07]        = &gbRom[tmpAddress + 0x3000];
  12.461 +		}
  12.462 +		else
  12.463 +		{
  12.464 +			value = value & 1;
  12.465 +			if (value == gbDataMBC5.mapperROMHighAddress)
  12.466 +				break;
  12.467 +
  12.468 +			tmpAddress = (gbDataMBC5.mapperROMBank << 14) | (value << 22);
  12.469 +
  12.470 +			tmpAddress &= gbRomSizeMask;
  12.471 +			gbDataMBC5.mapperROMHighAddress = value;
  12.472 +			gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.473 +			gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.474 +			gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.475 +			gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.476 +		}
  12.477 +		break;
  12.478 +	case 0x4000: // RAM bank select
  12.479 +		if (gbDataMBC5.isRumbleCartridge)
  12.480 +			value &= 0x07;
  12.481 +		else
  12.482 +			value &= 0x0f;
  12.483 +		if (value == gbDataMBC5.mapperRAMBank)
  12.484 +			break;
  12.485 +		tmpAddress  = value << 13;
  12.486 +		tmpAddress &= gbRamSizeMask;
  12.487 +		if (gbRamSize)
  12.488 +		{
  12.489 +			gbMemoryMap[0x0a] = &gbRam[tmpAddress];
  12.490 +			gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000];
  12.491 +
  12.492 +			gbDataMBC5.mapperRAMBank    = value;
  12.493 +			gbDataMBC5.mapperRAMAddress = tmpAddress;
  12.494 +		}
  12.495 +		break;
  12.496 +	}
  12.497 +}
  12.498 +
  12.499 +// MBC5 RAM write
  12.500 +void mapperMBC5RAM(u16 address, u8 value)
  12.501 +{
  12.502 +	if (gbDataMBC5.mapperRAMEnable)
  12.503 +	{
  12.504 +		if (gbRamSize)
  12.505 +		{
  12.506 +			gbWriteMemoryQuick(address, value);
  12.507 +			systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  12.508 +		}
  12.509 +	}
  12.510 +}
  12.511 +
  12.512 +void memoryUpdateMapMBC5()
  12.513 +{
  12.514 +	int tmpAddress = (gbDataMBC5.mapperROMBank << 14) |
  12.515 +	                 (gbDataMBC5.mapperROMHighAddress << 22) ;
  12.516 +
  12.517 +	tmpAddress       &= gbRomSizeMask;
  12.518 +	gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.519 +	gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.520 +	gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.521 +	gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.522 +
  12.523 +	if (gbRamSize)
  12.524 +	{
  12.525 +		tmpAddress        = gbDataMBC5.mapperRAMBank << 13;
  12.526 +		tmpAddress       &= gbRamSizeMask;
  12.527 +		gbMemoryMap[0x0a] = &gbRam[tmpAddress];
  12.528 +		gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000];
  12.529 +	}
  12.530 +}
  12.531 +
  12.532 +mapperMBC7 gbDataMBC7 = {
  12.533 +	0, // RAM enable
  12.534 +	1, // ROM bank
  12.535 +	0, // RAM bank
  12.536 +	0, // RAM address
  12.537 +	0, // chip select
  12.538 +	0, // ??
  12.539 +	0, // mapper state
  12.540 +	0, // buffer for receiving serial data
  12.541 +	0, // idle state
  12.542 +	0, // count of bits received
  12.543 +	0, // command received
  12.544 +	0, // address received
  12.545 +	0, // write enable
  12.546 +	0, // value to return on ram
  12.547 +};
  12.548 +
  12.549 +// MBC7 ROM write registers
  12.550 +void mapperMBC7ROM(u16 address, u8 value)
  12.551 +{
  12.552 +	int tmpAddress = 0;
  12.553 +
  12.554 +	switch (address & 0x6000)
  12.555 +	{
  12.556 +	case 0x0000:
  12.557 +		break;
  12.558 +	case 0x2000: // ROM bank select
  12.559 +		value = value & 0x7f;
  12.560 +		if (value == 0)
  12.561 +			value = 1;
  12.562 +
  12.563 +		if (value == gbDataMBC7.mapperROMBank)
  12.564 +			break;
  12.565 +
  12.566 +		tmpAddress = (value << 14);
  12.567 +
  12.568 +		tmpAddress &= gbRomSizeMask;
  12.569 +		gbDataMBC7.mapperROMBank = value;
  12.570 +		gbMemoryMap[0x04]        = &gbRom[tmpAddress];
  12.571 +		gbMemoryMap[0x05]        = &gbRom[tmpAddress + 0x1000];
  12.572 +		gbMemoryMap[0x06]        = &gbRom[tmpAddress + 0x2000];
  12.573 +		gbMemoryMap[0x07]        = &gbRom[tmpAddress + 0x3000];
  12.574 +		break;
  12.575 +	case 0x4000: // RAM bank select/enable
  12.576 +		if (value < 8)
  12.577 +		{
  12.578 +			tmpAddress        = (value&3) << 13;
  12.579 +			tmpAddress       &= gbRamSizeMask;
  12.580 +			gbMemoryMap[0x0a] = &gbMemory[0xa000];
  12.581 +			gbMemoryMap[0x0b] = &gbMemory[0xb000];
  12.582 +
  12.583 +			gbDataMBC7.mapperRAMBank    = value;
  12.584 +			gbDataMBC7.mapperRAMAddress = tmpAddress;
  12.585 +			gbDataMBC7.mapperRAMEnable  = 0;
  12.586 +		}
  12.587 +		else
  12.588 +		{
  12.589 +			gbDataMBC7.mapperRAMEnable = 0;
  12.590 +		}
  12.591 +		break;
  12.592 +	}
  12.593 +}
  12.594 +
  12.595 +// MBC7 read RAM
  12.596 +u8 mapperMBC7ReadRAM(u16 address)
  12.597 +{
  12.598 +	switch (address & 0xa0f0)
  12.599 +	{
  12.600 +	case 0xa000:
  12.601 +	case 0xa010:
  12.602 +	case 0xa060:
  12.603 +	case 0xa070:
  12.604 +		return 0;
  12.605 +	case 0xa020:
  12.606 +		// sensor X low byte
  12.607 +		return systemGetSensorX() & 255;
  12.608 +	case 0xa030:
  12.609 +		// sensor X high byte
  12.610 +		return systemGetSensorX() >> 8;
  12.611 +	case 0xa040:
  12.612 +		// sensor Y low byte
  12.613 +		return systemGetSensorY() & 255;
  12.614 +	case 0xa050:
  12.615 +		// sensor Y high byte
  12.616 +		return systemGetSensorY() >> 8;
  12.617 +	case 0xa080:
  12.618 +		return gbDataMBC7.value;
  12.619 +	}
  12.620 +	return 0xff;
  12.621 +}
  12.622 +
  12.623 +// MBC7 RAM write
  12.624 +void mapperMBC7RAM(u16 address, u8 value)
  12.625 +{
  12.626 +	if (address == 0xa080)
  12.627 +	{
  12.628 +		// special processing needed
  12.629 +		int oldCs = gbDataMBC7.cs, oldSk = gbDataMBC7.sk;
  12.630 +
  12.631 +		gbDataMBC7.cs = value>>7;
  12.632 +		gbDataMBC7.sk = (value>>6)&1;
  12.633 +
  12.634 +		if (!oldCs && gbDataMBC7.cs)
  12.635 +		{
  12.636 +			if (gbDataMBC7.state == 5)
  12.637 +			{
  12.638 +				if (gbDataMBC7.writeEnable)
  12.639 +				{
  12.640 +					gbWriteMemoryQuick(0xa000+gbDataMBC7.address*2, gbDataMBC7.buffer>>8);
  12.641 +					gbWriteMemoryQuick(0xa000+gbDataMBC7.address*2+1, gbDataMBC7.buffer&0xff);
  12.642 +					systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  12.643 +				}
  12.644 +				gbDataMBC7.state = 0;
  12.645 +				gbDataMBC7.value = 1;
  12.646 +			}
  12.647 +			else
  12.648 +			{
  12.649 +				gbDataMBC7.idle  = true;
  12.650 +				gbDataMBC7.state = 0;
  12.651 +			}
  12.652 +		}
  12.653 +
  12.654 +		if (!oldSk && gbDataMBC7.sk)
  12.655 +		{
  12.656 +			if (gbDataMBC7.idle)
  12.657 +			{
  12.658 +				if (value & 0x02)
  12.659 +				{
  12.660 +					gbDataMBC7.idle  = false;
  12.661 +					gbDataMBC7.count = 0;
  12.662 +					gbDataMBC7.state = 1;
  12.663 +				}
  12.664 +			}
  12.665 +			else
  12.666 +			{
  12.667 +				switch (gbDataMBC7.state)
  12.668 +				{
  12.669 +				case 1:
  12.670 +					// receiving command
  12.671 +					gbDataMBC7.buffer <<= 1;
  12.672 +					gbDataMBC7.buffer  |= (value & 0x02) ? 1 : 0;
  12.673 +					gbDataMBC7.count++;
  12.674 +					if (gbDataMBC7.count == 2)
  12.675 +					{
  12.676 +						// finished receiving command
  12.677 +						gbDataMBC7.state = 2;
  12.678 +						gbDataMBC7.count = 0;
  12.679 +						gbDataMBC7.code  = gbDataMBC7.buffer & 3;
  12.680 +					}
  12.681 +					break;
  12.682 +				case 2:
  12.683 +					// receive address
  12.684 +					gbDataMBC7.buffer <<= 1;
  12.685 +					gbDataMBC7.buffer  |= (value&0x02) ? 1 : 0;
  12.686 +					gbDataMBC7.count++;
  12.687 +					if (gbDataMBC7.count == 8)
  12.688 +					{
  12.689 +						// finish receiving
  12.690 +						gbDataMBC7.state   = 3;
  12.691 +						gbDataMBC7.count   = 0;
  12.692 +						gbDataMBC7.address = gbDataMBC7.buffer&0xff;
  12.693 +						if (gbDataMBC7.code == 0)
  12.694 +						{
  12.695 +							if ((gbDataMBC7.address>>6) == 0)
  12.696 +							{
  12.697 +								gbDataMBC7.writeEnable = 0;
  12.698 +								gbDataMBC7.state       = 0;
  12.699 +							}
  12.700 +							else if ((gbDataMBC7.address>>6) == 3)
  12.701 +							{
  12.702 +								gbDataMBC7.writeEnable = 1;
  12.703 +								gbDataMBC7.state       = 0;
  12.704 +							}
  12.705 +						}
  12.706 +					}
  12.707 +					break;
  12.708 +				case 3:
  12.709 +					gbDataMBC7.buffer <<= 1;
  12.710 +					gbDataMBC7.buffer  |= (value&0x02) ? 1 : 0;
  12.711 +					gbDataMBC7.count++;
  12.712 +
  12.713 +					switch (gbDataMBC7.code)
  12.714 +					{
  12.715 +					case 0:
  12.716 +						if (gbDataMBC7.count == 16)
  12.717 +						{
  12.718 +							if ((gbDataMBC7.address>>6) == 0)
  12.719 +							{
  12.720 +								gbDataMBC7.writeEnable = 0;
  12.721 +								gbDataMBC7.state       = 0;
  12.722 +							}
  12.723 +							else if ((gbDataMBC7.address>>6) == 1)
  12.724 +							{
  12.725 +								if (gbDataMBC7.writeEnable)
  12.726 +								{
  12.727 +									for (int i = 0; i < 256; i++)
  12.728 +									{
  12.729 +										gbWriteMemoryQuick(0xa000+i*2, gbDataMBC7.buffer >> 8);
  12.730 +										gbWriteMemoryQuick(0xa000+i*2+1, gbDataMBC7.buffer & 0xff);
  12.731 +										systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  12.732 +									}
  12.733 +								}
  12.734 +								gbDataMBC7.state = 5;
  12.735 +							}
  12.736 +							else if ((gbDataMBC7.address>>6) == 2)
  12.737 +							{
  12.738 +								if (gbDataMBC7.writeEnable)
  12.739 +								{
  12.740 +									for (int i = 0; i < 256; i++)
  12.741 +										WRITE16LE((u16 *)&gbMemory[0xa000+i*2], 0xffff);
  12.742 +									systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  12.743 +								}
  12.744 +								gbDataMBC7.state = 5;
  12.745 +							}
  12.746 +							else if ((gbDataMBC7.address>>6) == 3)
  12.747 +							{
  12.748 +								gbDataMBC7.writeEnable = 1;
  12.749 +								gbDataMBC7.state       = 0;
  12.750 +							}
  12.751 +							gbDataMBC7.count = 0;
  12.752 +						}
  12.753 +						break;
  12.754 +					case 1:
  12.755 +						if (gbDataMBC7.count == 16)
  12.756 +						{
  12.757 +							gbDataMBC7.count = 0;
  12.758 +							gbDataMBC7.state = 5;
  12.759 +							gbDataMBC7.value = 0;
  12.760 +						}
  12.761 +						break;
  12.762 +					case 2:
  12.763 +						if (gbDataMBC7.count == 1)
  12.764 +						{
  12.765 +							gbDataMBC7.state  = 4;
  12.766 +							gbDataMBC7.count  = 0;
  12.767 +							gbDataMBC7.buffer = (gbReadMemoryQuick(0xa000+gbDataMBC7.address*2)<<8)|
  12.768 +							                    (gbReadMemoryQuick(0xa000+gbDataMBC7.address*2+1));
  12.769 +						}
  12.770 +						break;
  12.771 +					case 3:
  12.772 +						if (gbDataMBC7.count == 16)
  12.773 +						{
  12.774 +							gbDataMBC7.count  = 0;
  12.775 +							gbDataMBC7.state  = 5;
  12.776 +							gbDataMBC7.value  = 0;
  12.777 +							gbDataMBC7.buffer = 0xffff;
  12.778 +						}
  12.779 +						break;
  12.780 +					}
  12.781 +					break;
  12.782 +				}
  12.783 +			}
  12.784 +		}
  12.785 +
  12.786 +		if (oldSk && !gbDataMBC7.sk)
  12.787 +		{
  12.788 +			if (gbDataMBC7.state == 4)
  12.789 +			{
  12.790 +				gbDataMBC7.value    = (gbDataMBC7.buffer & 0x8000) ? 1 : 0;
  12.791 +				gbDataMBC7.buffer <<= 1;
  12.792 +				gbDataMBC7.count++;
  12.793 +				if (gbDataMBC7.count == 16)
  12.794 +				{
  12.795 +					gbDataMBC7.count = 0;
  12.796 +					gbDataMBC7.state = 0;
  12.797 +				}
  12.798 +			}
  12.799 +		}
  12.800 +	}
  12.801 +}
  12.802 +
  12.803 +void memoryUpdateMapMBC7()
  12.804 +{
  12.805 +	int tmpAddress = (gbDataMBC5.mapperROMBank << 14);
  12.806 +
  12.807 +	tmpAddress       &= gbRomSizeMask;
  12.808 +	gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.809 +	gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.810 +	gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.811 +	gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.812 +}
  12.813 +
  12.814 +mapperHuC1 gbDataHuC1 = {
  12.815 +	0, // RAM enable
  12.816 +	1, // ROM bank
  12.817 +	0, // RAM bank
  12.818 +	0, // memory model
  12.819 +	0, // ROM high address
  12.820 +	0 // RAM address
  12.821 +};
  12.822 +
  12.823 +// HuC1 ROM write registers
  12.824 +void mapperHuC1ROM(u16 address, u8 value)
  12.825 +{
  12.826 +	int tmpAddress = 0;
  12.827 +
  12.828 +	switch (address & 0x6000)
  12.829 +	{
  12.830 +	case 0x0000: // RAM enable register
  12.831 +		gbDataHuC1.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0);
  12.832 +		break;
  12.833 +	case 0x2000: // ROM bank select
  12.834 +		value = value & 0x3f;
  12.835 +		if (value == 0)
  12.836 +			value = 1;
  12.837 +		if (value == gbDataHuC1.mapperROMBank)
  12.838 +			break;
  12.839 +
  12.840 +		tmpAddress = value << 14;
  12.841 +
  12.842 +		tmpAddress &= gbRomSizeMask;
  12.843 +		gbDataHuC1.mapperROMBank = value;
  12.844 +		gbMemoryMap[0x04]        = &gbRom[tmpAddress];
  12.845 +		gbMemoryMap[0x05]        = &gbRom[tmpAddress + 0x1000];
  12.846 +		gbMemoryMap[0x06]        = &gbRom[tmpAddress + 0x2000];
  12.847 +		gbMemoryMap[0x07]        = &gbRom[tmpAddress + 0x3000];
  12.848 +		break;
  12.849 +	case 0x4000: // RAM bank select
  12.850 +		if (gbDataHuC1.mapperMemoryModel == 1)
  12.851 +		{
  12.852 +			// 4/32 model, RAM bank switching provided
  12.853 +			value = value & 0x03;
  12.854 +			if (value == gbDataHuC1.mapperRAMBank)
  12.855 +				break;
  12.856 +			tmpAddress                  = value << 13;
  12.857 +			tmpAddress                 &= gbRamSizeMask;
  12.858 +			gbMemoryMap[0x0a]           = &gbRam[tmpAddress];
  12.859 +			gbMemoryMap[0x0b]           = &gbRam[tmpAddress + 0x1000];
  12.860 +			gbDataHuC1.mapperRAMBank    = value;
  12.861 +			gbDataHuC1.mapperRAMAddress = tmpAddress;
  12.862 +		}
  12.863 +		else
  12.864 +		{
  12.865 +			// 16/8, set the high address
  12.866 +			gbDataHuC1.mapperROMHighAddress = value & 0x03;
  12.867 +			tmpAddress        = gbDataHuC1.mapperROMBank << 14;
  12.868 +			tmpAddress       |= (gbDataHuC1.mapperROMHighAddress) << 19;
  12.869 +			tmpAddress       &= gbRomSizeMask;
  12.870 +			gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.871 +			gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.872 +			gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.873 +			gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.874 +		}
  12.875 +		break;
  12.876 +	case 0x6000: // memory model select
  12.877 +		gbDataHuC1.mapperMemoryModel = value & 1;
  12.878 +		break;
  12.879 +	}
  12.880 +}
  12.881 +
  12.882 +// HuC1 RAM write
  12.883 +void mapperHuC1RAM(u16 address, u8 value)
  12.884 +{
  12.885 +	if (gbDataHuC1.mapperRAMEnable)
  12.886 +	{
  12.887 +		if (gbRamSize)
  12.888 +		{
  12.889 +			gbWriteMemoryQuick(address, value);
  12.890 +			systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  12.891 +		}
  12.892 +	}
  12.893 +}
  12.894 +
  12.895 +void memoryUpdateMapHuC1()
  12.896 +{
  12.897 +	int tmpAddress = gbDataHuC1.mapperROMBank << 14;
  12.898 +
  12.899 +	tmpAddress &= gbRomSizeMask;
  12.900 +
  12.901 +	gbMemoryMap[0x04] = &gbRom[tmpAddress];
  12.902 +	gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
  12.903 +	gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
  12.904 +	gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
  12.905 +
  12.906 +	if (gbRamSize)
  12.907 +	{
  12.908 +		tmpAddress        = gbDataHuC1.mapperRAMBank << 13;
  12.909 +		tmpAddress       &= gbRamSizeMask;
  12.910 +		gbMemoryMap[0x0a] = &gbRam[tmpAddress];
  12.911 +		gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000];
  12.912 +	}
  12.913 +}
  12.914 +
  12.915 +mapperHuC3 gbDataHuC3 = {
  12.916 +	0, // RAM enable
  12.917 +	1, // ROM bank
  12.918 +	0, // RAM bank
  12.919 +	0, // RAM address
  12.920 +	0, // RAM flag
  12.921 +	0 // RAM read value
  12.922 +};
  12.923 +
  12.924 +// HuC3 ROM write registers
  12.925 +void mapperHuC3ROM(u16 address, u8 value)
  12.926 +{
  12.927 +	int tmpAddress = 0;
  12.928 +
  12.929 +	switch (address & 0x6000)
  12.930 +	{
  12.931 +	case 0x0000: // RAM enable register
  12.932 +		gbDataHuC3.mapperRAMEnable = (value == 0x0a ? 1 : 0);
  12.933 +		gbDataHuC3.mapperRAMFlag   = value;
  12.934 +		if (gbDataHuC3.mapperRAMFlag != 0x0a)
  12.935 +			gbDataHuC3.mapperRAMBank = -1;
  12.936 +		break;
  12.937 +	case 0x2000: // ROM bank select
  12.938 +		value = value & 0x7f;
  12.939 +		if (value == 0)
  12.940 +			value = 1;
  12.941 +		if (value == gbDataHuC3.mapperROMBank)
  12.942 +			break;
  12.943 +
  12.944 +		tmpAddress = value << 14;
  12.945 +
  12.946 +		tmpAddress &= gbRomSizeMask;
  12.947 +		gbDataHuC3.mapperROMBank = value;
  12.948 +		gbMemoryMap[0x04]        = &gbRom[tmpAddress];
  12.949 +		gbMemoryMap[0x05]        = &gbRom[tmpAddress + 0x1000];
  12.950 +		gbMemoryMap[0x06]        = &gbRom[tmpAddress + 0x2000];
  12.951 +		gbMemoryMap[0x07]        = &gbRom[tmpAddress + 0x3000];
  12.952 +		break;
  12.953 +	case 0x4000: // RAM bank select
  12.954 +		value = value & 0x03;
  12.955 +		if (value == gbDataHuC3.mapperRAMBank)
  12.956 +			break;
  12.957 +		tmpAddress                  = value << 13;
  12.958 +		tmpAddress                 &= gbRamSizeMask;
  12.959 +		gbMemoryMap[0x0a]           = &gbRam[tmpAddress];
  12.960 +		gbMemoryMap[0x0b]           = &gbRam[tmpAddress + 0x1000];
  12.961 +		gbDataHuC3.mapperRAMBank    = value;
  12.962 +		gbDataHuC3.mapperRAMAddress = tmpAddress;
  12.963 +		break;
  12.964 +	case 0x6000: // nothing to do!
  12.965 +		break;
  12.966 +	}
  12.967 +}
  12.968 +
  12.969 +// HuC3 read RAM
  12.970 +u8 mapperHuC3ReadRAM(u16 address)
  12.971 +{
  12.972 +	if (gbDataHuC3.mapperRAMFlag > 0x0b &&
  12.973 +	    gbDataHuC3.mapperRAMFlag < 0x0e)
  12.974 +	{
  12.975 +		if (gbDataHuC3.mapperRAMFlag != 0x0c)
  12.976 +			return 1;
  12.977 +		return gbDataHuC3.mapperRAMValue;
  12.978 +	}
  12.979 +	else
  12.980 +		return gbReadMemoryQuick(address);
  12.981 +}
  12.982 +
  12.983 +// HuC3 RAM write
  12.984 +void mapperHuC3RAM(u16 address, u8 value)
  12.985 +{
  12.986 +	int32 *p;
  12.987 +
  12.988 +	if (gbDataHuC3.mapperRAMFlag < 0x0b ||
  12.989 +	    gbDataHuC3.mapperRAMFlag > 0x0e)
  12.990 +	{
  12.991 +		if (gbDataHuC3.mapperRAMEnable)
  12.992 +		{
  12.993 +			if (gbRamSize)
  12.994 +			{
  12.995 +				gbWriteMemoryQuick(address, value);
  12.996 +				systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  12.997 +			}
  12.998 +		}
  12.999 +	}
 12.1000 +	else
 12.1001 +	{
 12.1002 +		if (gbDataHuC3.mapperRAMFlag == 0x0b)
 12.1003 +		{
 12.1004 +			if (value == 0x62)
 12.1005 +			{
 12.1006 +				gbDataHuC3.mapperRAMValue = 1;
 12.1007 +			}
 12.1008 +			else
 12.1009 +			{
 12.1010 +				switch (value & 0xf0)
 12.1011 +				{
 12.1012 +				case 0x10:
 12.1013 +					p = &gbDataHuC3.mapperRegister2;
 12.1014 +					gbDataHuC3.mapperRAMValue = *(p+gbDataHuC3.mapperRegister1++);
 12.1015 +					if (gbDataHuC3.mapperRegister1 > 6)
 12.1016 +						gbDataHuC3.mapperRegister1 = 0;
 12.1017 +					break;
 12.1018 +				case 0x30:
 12.1019 +					p = &gbDataHuC3.mapperRegister2;
 12.1020 +					*(p+gbDataHuC3.mapperRegister1++) = value & 0x0f;
 12.1021 +					if (gbDataHuC3.mapperRegister1 > 6)
 12.1022 +						gbDataHuC3.mapperRegister1 = 0;
 12.1023 +					gbDataHuC3.mapperAddress =
 12.1024 +					    (gbDataHuC3.mapperRegister6 << 24) |
 12.1025 +					    (gbDataHuC3.mapperRegister5 << 16) |
 12.1026 +					    (gbDataHuC3.mapperRegister4 <<  8) |
 12.1027 +					    (gbDataHuC3.mapperRegister3 <<  4) |
 12.1028 +					    (gbDataHuC3.mapperRegister2);
 12.1029 +					break;
 12.1030 +				case 0x40:
 12.1031 +					gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0xf0) |
 12.1032 +					                             (value & 0x0f);
 12.1033 +					gbDataHuC3.mapperRegister2 = (gbDataHuC3.mapperAddress & 0x0f);
 12.1034 +					gbDataHuC3.mapperRegister3 = ((gbDataHuC3.mapperAddress>>4)&0x0f);
 12.1035 +					gbDataHuC3.mapperRegister4 = ((gbDataHuC3.mapperAddress>>8)&0x0f);
 12.1036 +					gbDataHuC3.mapperRegister5 = ((gbDataHuC3.mapperAddress>>16)&0x0f);
 12.1037 +					gbDataHuC3.mapperRegister6 = ((gbDataHuC3.mapperAddress>>24)&0x0f);
 12.1038 +					gbDataHuC3.mapperRegister7 = 0;
 12.1039 +					gbDataHuC3.mapperRegister8 = 0;
 12.1040 +					gbDataHuC3.mapperRAMValue  = 0;
 12.1041 +					break;
 12.1042 +				case 0x50:
 12.1043 +					gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0x0f) |
 12.1044 +					                             ((value << 4)&0x0f);
 12.1045 +					break;
 12.1046 +				default:
 12.1047 +					gbDataHuC3.mapperRAMValue = 1;
 12.1048 +					break;
 12.1049 +				}
 12.1050 +			}
 12.1051 +		}
 12.1052 +	}
 12.1053 +}
 12.1054 +
 12.1055 +void memoryUpdateMapHuC3()
 12.1056 +{
 12.1057 +	int tmpAddress = gbDataHuC3.mapperROMBank << 14;
 12.1058 +
 12.1059 +	tmpAddress       &= gbRomSizeMask;
 12.1060 +	gbMemoryMap[0x04] = &gbRom[tmpAddress];
 12.1061 +	gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000];
 12.1062 +	gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000];
 12.1063 +	gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
 12.1064 +
 12.1065 +	if (gbRamSize)
 12.1066 +	{
 12.1067 +		tmpAddress        = gbDataHuC3.mapperRAMBank << 13;
 12.1068 +		tmpAddress       &= gbRamSizeMask;
 12.1069 +		gbMemoryMap[0x0a] = &gbRam[tmpAddress];
 12.1070 +		gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000];
 12.1071 +	}
 12.1072 +}
 12.1073 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/gb/gbMemory.h	Sat Mar 03 11:44:47 2012 -0600
    13.3 @@ -0,0 +1,142 @@
    13.4 +#ifndef VBA_GB_MEMORY_H
    13.5 +#define VBA_GB_MEMORY_H
    13.6 +
    13.7 +#if _MSC_VER > 1000
    13.8 +#pragma once
    13.9 +#endif // _MSC_VER > 1000
   13.10 +
   13.11 +#include "../Port.h"
   13.12 +
   13.13 +struct mapperMBC1
   13.14 +{
   13.15 +	int32 mapperRAMEnable;
   13.16 +	int32 mapperROMBank;
   13.17 +	int32 mapperRAMBank;
   13.18 +	int32 mapperMemoryModel;
   13.19 +	int32 mapperROMHighAddress;
   13.20 +	int32 mapperRAMAddress;
   13.21 +};
   13.22 +
   13.23 +struct mapperMBC2
   13.24 +{
   13.25 +	int32 mapperRAMEnable;
   13.26 +	int32 mapperROMBank;
   13.27 +};
   13.28 +
   13.29 +struct mapperMBC3
   13.30 +{
   13.31 +	int32  mapperRAMEnable;
   13.32 +	int32  mapperROMBank;
   13.33 +	int32  mapperRAMBank;
   13.34 +	int32  mapperRAMAddress;
   13.35 +	int32  mapperClockLatch;
   13.36 +	int32  mapperClockRegister;
   13.37 +	int32  mapperSeconds;
   13.38 +	int32  mapperMinutes;
   13.39 +	int32  mapperHours;
   13.40 +	int32  mapperDays;
   13.41 +	int32  mapperControl;
   13.42 +	int32  mapperLSeconds;
   13.43 +	int32  mapperLMinutes;
   13.44 +	int32  mapperLHours;
   13.45 +	int32  mapperLDays;
   13.46 +	int32  mapperLControl;
   13.47 +	//time_t mapperLastTime;
   13.48 +	u32 mapperLastTime;
   13.49 +};
   13.50 +
   13.51 +struct mapperMBC5
   13.52 +{
   13.53 +	int32 mapperRAMEnable;
   13.54 +	int32 mapperROMBank;
   13.55 +	int32 mapperRAMBank;
   13.56 +	int32 mapperROMHighAddress;
   13.57 +	int32 mapperRAMAddress;
   13.58 +	int32 isRumbleCartridge;
   13.59 +};
   13.60 +
   13.61 +struct mapperMBC7
   13.62 +{
   13.63 +	int32 mapperRAMEnable;
   13.64 +	int32 mapperROMBank;
   13.65 +	int32 mapperRAMBank;
   13.66 +	int32 mapperRAMAddress;
   13.67 +	int32 cs;
   13.68 +	int32 sk;
   13.69 +	int32 state;
   13.70 +	int32 buffer;
   13.71 +	int32 idle;
   13.72 +	int32 count;
   13.73 +	int32 code;
   13.74 +	int32 address;
   13.75 +	int32 writeEnable;
   13.76 +	int32 value;
   13.77 +};
   13.78 +
   13.79 +struct mapperHuC1
   13.80 +{
   13.81 +	int32 mapperRAMEnable;
   13.82 +	int32 mapperROMBank;
   13.83 +	int32 mapperRAMBank;
   13.84 +	int32 mapperMemoryModel;
   13.85 +	int32 mapperROMHighAddress;
   13.86 +	int32 mapperRAMAddress;
   13.87 +};
   13.88 +
   13.89 +struct mapperHuC3
   13.90 +{
   13.91 +	int32 mapperRAMEnable;
   13.92 +	int32 mapperROMBank;
   13.93 +	int32 mapperRAMBank;
   13.94 +	int32 mapperRAMAddress;
   13.95 +	int32 mapperAddress;
   13.96 +	int32 mapperRAMFlag;
   13.97 +	int32 mapperRAMValue;
   13.98 +	int32 mapperRegister1;
   13.99 +	int32 mapperRegister2;
  13.100 +	int32 mapperRegister3;
  13.101 +	int32 mapperRegister4;
  13.102 +	int32 mapperRegister5;
  13.103 +	int32 mapperRegister6;
  13.104 +	int32 mapperRegister7;
  13.105 +	int32 mapperRegister8;
  13.106 +};
  13.107 +
  13.108 +extern mapperMBC1 gbDataMBC1;
  13.109 +extern mapperMBC2 gbDataMBC2;
  13.110 +extern mapperMBC3 gbDataMBC3;
  13.111 +extern mapperMBC5 gbDataMBC5;
  13.112 +extern mapperHuC1 gbDataHuC1;
  13.113 +extern mapperHuC3 gbDataHuC3;
  13.114 +
  13.115 +void mapperMBC1ROM(u16, u8);
  13.116 +void mapperMBC1RAM(u16, u8);
  13.117 +void mapperMBC2ROM(u16, u8);
  13.118 +void mapperMBC2RAM(u16, u8);
  13.119 +void mapperMBC3ROM(u16, u8);
  13.120 +void mapperMBC3RAM(u16, u8);
  13.121 +u8   mapperMBC3ReadRAM(u16);
  13.122 +void mapperMBC5ROM(u16, u8);
  13.123 +void mapperMBC5RAM(u16, u8);
  13.124 +void mapperMBC7ROM(u16, u8);
  13.125 +void mapperMBC7RAM(u16, u8);
  13.126 +u8   mapperMBC7ReadRAM(u16);
  13.127 +void mapperHuC1ROM(u16, u8);
  13.128 +void mapperHuC1RAM(u16, u8);
  13.129 +void mapperHuC3ROM(u16, u8);
  13.130 +void mapperHuC3RAM(u16, u8);
  13.131 +u8   mapperHuC3ReadRAM(u16);
  13.132 +
  13.133 +//extern void (*mapper)(u16,u8);
  13.134 +//extern void (*mapperRAM)(u16,u8);
  13.135 +//extern u8 (*mapperReadRAM)(u16);
  13.136 +
  13.137 +extern void memoryUpdateMapMBC1();
  13.138 +extern void memoryUpdateMapMBC2();
  13.139 +extern void memoryUpdateMapMBC3();
  13.140 +extern void memoryUpdateMapMBC5();
  13.141 +extern void memoryUpdateMapMBC7();
  13.142 +extern void memoryUpdateMapHuC1();
  13.143 +extern void memoryUpdateMapHuC3();
  13.144 +
  13.145 +#endif // VBA_GB_MEMORY
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/gb/gbPrinter.cpp	Sat Mar 03 11:44:47 2012 -0600
    14.3 @@ -0,0 +1,234 @@
    14.4 +#include <cstdio>
    14.5 +#include <cstring>
    14.6 +
    14.7 +#include "../common/System.h"
    14.8 +#include "gbPrinter.h"
    14.9 +
   14.10 +u8  gbPrinterStatus = 0;
   14.11 +int gbPrinterState  = 0;
   14.12 +u8  gbPrinterData[0x280*9];
   14.13 +u8  gbPrinterPacket[0x400];
   14.14 +int gbPrinterCount     = 0;
   14.15 +int gbPrinterDataCount = 0;
   14.16 +int gbPrinterDataSize  = 0;
   14.17 +int gbPrinterResult    = 0;
   14.18 +
   14.19 +bool gbPrinterCheckCRC()
   14.20 +{
   14.21 +	u16 crc = 0;
   14.22 +
   14.23 +	for (int i = 2; i < (6+gbPrinterDataSize); i++)
   14.24 +	{
   14.25 +		crc += gbPrinterPacket[i];
   14.26 +	}
   14.27 +
   14.28 +	int msgCrc = gbPrinterPacket[6+gbPrinterDataSize] +
   14.29 +	             (gbPrinterPacket[7+gbPrinterDataSize]<<8);
   14.30 +
   14.31 +	return msgCrc == crc;
   14.32 +}
   14.33 +
   14.34 +void gbPrinterReset()
   14.35 +{
   14.36 +	gbPrinterState     = 0;
   14.37 +	gbPrinterDataSize  = 0;
   14.38 +	gbPrinterDataCount = 0;
   14.39 +	gbPrinterCount     = 0;
   14.40 +	gbPrinterStatus    = 0;
   14.41 +	gbPrinterResult    = 0;
   14.42 +}
   14.43 +
   14.44 +void gbPrinterShowData()
   14.45 +{
   14.46 +	systemGbPrint(gbPrinterData,
   14.47 +	              gbPrinterPacket[6],
   14.48 +	              gbPrinterPacket[7],
   14.49 +	              gbPrinterPacket[8],
   14.50 +	              gbPrinterPacket[9]);
   14.51 +	/*
   14.52 +	   allegro_init();
   14.53 +	   install_keyboard();
   14.54 +	   set_gfx_mode(GFX_AUTODETECT, 160, 144, 0, 0);
   14.55 +	   PALETTE pal;
   14.56 +	   pal[0].r = 255;
   14.57 +	   pal[0].g = 255;
   14.58 +	   pal[0].b = 255;
   14.59 +	   pal[1].r = 168;
   14.60 +	   pal[1].g = 168;
   14.61 +	   pal[1].b = 168;
   14.62 +	   pal[2].r = 96;
   14.63 +	   pal[2].g = 96;
   14.64 +	   pal[2].b = 96;
   14.65 +	   pal[3].r = 0;
   14.66 +	   pal[3].g = 0;
   14.67 +	   pal[3].b = 0;
   14.68 +	   set_palette(pal);
   14.69 +	   acquire_screen();
   14.70 +	   u8 *data = gbPrinterData;
   14.71 +	   for(int y = 0; y < 0x12; y++) {
   14.72 +	   for(int x = 0; x < 0x14; x++) {
   14.73 +	    for(int k = 0; k < 8; k++) {
   14.74 +	      int a = *data++;
   14.75 +	      int b = *data++;
   14.76 +	      for(int j = 0; j < 8; j++) {
   14.77 +	        int mask = 1 << (7-j);
   14.78 +	        int c = 0;
   14.79 +	        if(a & mask)
   14.80 +	          c++;
   14.81 +	        if(b & mask)
   14.82 +	          c+=2;
   14.83 +	        putpixel(screen, x*8+j, y*8+k, c);
   14.84 +	      }
   14.85 +	    }
   14.86 +	   }
   14.87 +	   }
   14.88 +	   release_screen();
   14.89 +	   while(!keypressed()) {
   14.90 +	   }
   14.91 +	 */
   14.92 +}
   14.93 +
   14.94 +void gbPrinterReceiveData()
   14.95 +{
   14.96 +	if (gbPrinterPacket[3]) // compressed
   14.97 +	{
   14.98 +		u8 *data = &gbPrinterPacket[6];
   14.99 +		u8 *dest = &gbPrinterData[gbPrinterDataCount];
  14.100 +		int len  = 0;
  14.101 +		while (len < gbPrinterDataSize)
  14.102 +		{
  14.103 +			u8 control = *data++;
  14.104 +			if (control & 0x80) // repeated data
  14.105 +			{
  14.106 +				control &= 0x7f;
  14.107 +				control += 2;
  14.108 +				memset(dest, *data++, control);
  14.109 +				len  += control;
  14.110 +				dest += control;
  14.111 +			}
  14.112 +			else // raw data
  14.113 +			{
  14.114 +				control++;
  14.115 +				memcpy(dest, data, control);
  14.116 +				dest += control;
  14.117 +				data += control;
  14.118 +				len  += control;
  14.119 +			}
  14.120 +		}
  14.121 +	}
  14.122 +	else
  14.123 +	{
  14.124 +		memcpy(&gbPrinterData[gbPrinterDataCount],
  14.125 +		       &gbPrinterPacket[6],
  14.126 +		       gbPrinterDataSize);
  14.127 +		gbPrinterDataCount += gbPrinterDataSize;
  14.128 +	}
  14.129 +}
  14.130 +
  14.131 +void gbPrinterCommand()
  14.132 +{
  14.133 +	switch (gbPrinterPacket[2])
  14.134 +	{
  14.135 +	case 0x01:
  14.136 +		// reset/initialize packet
  14.137 +		gbPrinterDataCount = 0;
  14.138 +		gbPrinterStatus    = 0;
  14.139 +		break;
  14.140 +	case 0x02:
  14.141 +		// print packet
  14.142 +		gbPrinterShowData();
  14.143 +		break;
  14.144 +	case 0x04:
  14.145 +		// data packet
  14.146 +		gbPrinterReceiveData();
  14.147 +		break;
  14.148 +	case 0x0f:
  14.149 +		// NUL packet
  14.150 +		break;
  14.151 +	}
  14.152 +}
  14.153 +
  14.154 +u8 gbPrinterSend(u8 byte)
  14.155 +{
  14.156 +	switch (gbPrinterState)
  14.157 +	{
  14.158 +	case 0:
  14.159 +		gbPrinterCount = 0;
  14.160 +		// receiving preamble
  14.161 +		if (byte == 0x88)
  14.162 +		{
  14.163 +			gbPrinterPacket[gbPrinterCount++] = byte;
  14.164 +			gbPrinterState++;
  14.165 +		}
  14.166 +		else
  14.167 +		{
  14.168 +			// todo: handle failure
  14.169 +			gbPrinterReset();
  14.170 +		}
  14.171 +		break;
  14.172 +	case 1:
  14.173 +		// receiving preamble
  14.174 +		if (byte == 0x33)
  14.175 +		{
  14.176 +			gbPrinterPacket[gbPrinterCount++] = byte;
  14.177 +			gbPrinterState++;
  14.178 +		}
  14.179 +		else
  14.180 +		{
  14.181 +			// todo: handle failure
  14.182 +			gbPrinterReset();
  14.183 +		}
  14.184 +		break;
  14.185 +	case 2:
  14.186 +		// receiving header
  14.187 +		gbPrinterPacket[gbPrinterCount++] = byte;
  14.188 +		if (gbPrinterCount == 6)
  14.189 +		{
  14.190 +			gbPrinterState++;
  14.191 +			gbPrinterDataSize = gbPrinterPacket[4] + (gbPrinterPacket[5]<<8);
  14.192 +		}
  14.193 +		break;
  14.194 +	case 3:
  14.195 +		// receiving data
  14.196 +		if (gbPrinterDataSize)
  14.197 +		{
  14.198 +			gbPrinterPacket[gbPrinterCount++] = byte;
  14.199 +			if (gbPrinterCount == (6+gbPrinterDataSize))
  14.200 +			{
  14.201 +				gbPrinterState++;
  14.202 +			}
  14.203 +			break;
  14.204 +		}
  14.205 +		gbPrinterState++;
  14.206 +	// intentionally move to next if no data to receive
  14.207 +	case 4:
  14.208 +		// receiving CRC
  14.209 +		gbPrinterPacket[gbPrinterCount++] = byte;
  14.210 +		gbPrinterState++;
  14.211 +		break;
  14.212 +	case 5:
  14.213 +		// receiving CRC-2
  14.214 +		gbPrinterPacket[gbPrinterCount++] = byte;
  14.215 +		if (gbPrinterCheckCRC())
  14.216 +		{
  14.217 +			gbPrinterCommand();
  14.218 +		}
  14.219 +		gbPrinterState++;
  14.220 +		break;
  14.221 +	case 6:
  14.222 +		// receiving dummy 1
  14.223 +		gbPrinterPacket[gbPrinterCount++] = byte;
  14.224 +		gbPrinterResult = 0x81;
  14.225 +		gbPrinterState++;
  14.226 +		break;
  14.227 +	case 7:
  14.228 +		// receiving dummy 2
  14.229 +		gbPrinterPacket[gbPrinterCount++] = byte;
  14.230 +		gbPrinterResult = gbPrinterStatus;
  14.231 +		gbPrinterState  = 0;
  14.232 +		gbPrinterCount  = 0;
  14.233 +		break;
  14.234 +	}
  14.235 +	return gbPrinterResult;
  14.236 +}
  14.237 +
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/gb/gbPrinter.h	Sat Mar 03 11:44:47 2012 -0600
    15.3 @@ -0,0 +1,10 @@
    15.4 +#ifndef VBA_GB_PRINTER_H
    15.5 +#define VBA_GB_PRINTER_H
    15.6 +
    15.7 +#if _MSC_VER > 1000
    15.8 +#pragma once
    15.9 +#endif // _MSC_VER > 1000
   15.10 +
   15.11 +extern u8 gbPrinterSend(u8 byte);
   15.12 +
   15.13 +#endif // VBA_GB_PRINTER_H
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/gb/gbSGB.cpp	Sat Mar 03 11:44:47 2012 -0600
    16.3 @@ -0,0 +1,997 @@
    16.4 +#include <cstdlib>
    16.5 +#include <cstring>
    16.6 +
    16.7 +#include "../common/System.h"
    16.8 +#include "../common/Util.h"
    16.9 +#include "GB.h"
   16.10 +#include "gbGlobals.h"
   16.11 +#include "../common/movie.h"
   16.12 +
   16.13 +extern u8 * pix;
   16.14 +
   16.15 +#define GBSGB_NONE            0
   16.16 +#define GBSGB_RESET           1
   16.17 +#define GBSGB_PACKET_TRANSMIT 2
   16.18 +
   16.19 +u8 gbSgbBorderChar [32 * 256];
   16.20 +u8 gbSgbBorder [2048];
   16.21 +
   16.22 +int32 gbSgbCGBSupport	   = 0;
   16.23 +int32 gbSgbMask			   = 0;
   16.24 +int32 gbSgbMode			   = 0;
   16.25 +int32 gbSgbPacketState	   = GBSGB_NONE;
   16.26 +int32 gbSgbBit			   = 0;
   16.27 +int32 gbSgbPacketTimeout   = 0;
   16.28 +int32 GBSGB_PACKET_TIMEOUT = 66666;
   16.29 +u8	  gbSgbPacket[16 * 7];
   16.30 +int32 gbSgbPacketNBits		 = 0;
   16.31 +int32 gbSgbPacketByte		 = 0;
   16.32 +int32 gbSgbPacketNumber		 = 0;
   16.33 +int32 gbSgbMultiplayer		 = 0;
   16.34 +int32 gbSgbFourPlayers		 = 0;
   16.35 +u8	  gbSgbNextController	 = 0x0f;
   16.36 +u8	  gbSgbReadingController = 0;
   16.37 +u16	  gbSgbSCPPalette[4 * 512];
   16.38 +u8	  gbSgbATF[20 * 18];
   16.39 +u8	  gbSgbATFList[45 * 20 * 18];
   16.40 +u8	  gbSgbScreenBuffer[4160];
   16.41 +
   16.42 +inline void gbSgbDraw24Bit(u8 *p, u16 v)
   16.43 +{
   16.44 +	*((u32 *) p) = systemColorMap32[v];
   16.45 +}
   16.46 +
   16.47 +inline void gbSgbDraw32Bit(u32 *p, u16 v)
   16.48 +{
   16.49 +	*p = systemColorMap32[v];
   16.50 +}
   16.51 +
   16.52 +inline void gbSgbDraw16Bit(u16 *p, u16 v)
   16.53 +{
   16.54 +	*p = systemColorMap16[v];
   16.55 +}
   16.56 +
   16.57 +void gbSgbReset()
   16.58 +{
   16.59 +	gbSgbPacketTimeout = 0;
   16.60 +	gbSgbCGBSupport	   = 0;
   16.61 +	gbSgbMask			   = 0;
   16.62 +	gbSgbPacketState	   = GBSGB_NONE;
   16.63 +	gbSgbBit			   = 0;
   16.64 +	gbSgbPacketNBits	   = 0;
   16.65 +	gbSgbPacketNumber	   = 0;
   16.66 +	gbSgbMultiplayer	   = 0;
   16.67 +	gbSgbFourPlayers	   = 0;
   16.68 +	gbSgbNextController	   = 0x0f;
   16.69 +	gbSgbReadingController = 0;
   16.70 +
   16.71 +	memset(gbSgbSCPPalette, 0, 512 * 4);
   16.72 +	memset(gbSgbATF, 0, 20 * 18);
   16.73 +	memset(gbSgbATFList, 0, 45 * 20 * 18);
   16.74 +	memset(gbSgbPacket, 0, 16 * 7);
   16.75 +	memset(gbSgbBorderChar, 0, 32 * 256);
   16.76 +	memset(gbSgbBorder, 0, 2048);
   16.77 +
   16.78 +	int i;
   16.79 +	for (i = 1; i < 2048; i += 2)
   16.80 +	{
   16.81 +		gbSgbBorder[i] = 1 << 2;
   16.82 +	}
   16.83 +
   16.84 +	for (i = 0; i < 4; i++)
   16.85 +	{
   16.86 +		gbPalette[i * 4]	 = (0x1f) | (0x1f << 5) | (0x1f << 10);
   16.87 +		gbPalette[i * 4 + 1] = (0x15) | (0x15 << 5) | (0x15 << 10);
   16.88 +		gbPalette[i * 4 + 2] = (0x0c) | (0x0c << 5) | (0x0c << 10);
   16.89 +		gbPalette[i * 4 + 3] = 0;
   16.90 +	}
   16.91 +}
   16.92 +
   16.93 +void gbSgbInit()
   16.94 +{
   16.95 +	gbSgbReset();
   16.96 +}
   16.97 +
   16.98 +void gbSgbShutdown()
   16.99 +{
  16.100 +	memset(gbSgbBorderChar, 0, 32 * 256);
  16.101 +	memset(gbSgbBorder, 0, 2048);
  16.102 +}
  16.103 +
  16.104 +void gbSgbFillScreen(u16 color)
  16.105 +{
  16.106 +	switch (systemColorDepth)
  16.107 +	{
  16.108 +	case 16:
  16.109 +	{
  16.110 +		for (int y = 0; y < 144; y++)
  16.111 +		{
  16.112 +			int yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 2) +
  16.113 +			            gbBorderColumnSkip;
  16.114 +			u16 *dest = (u16 *)pix + yLine;
  16.115 +			for (register int x = 0; x < 160; x++)
  16.116 +				gbSgbDraw16Bit(dest++, color);
  16.117 +		}
  16.118 +	}
  16.119 +	break;
  16.120 +	case 24:
  16.121 +	{
  16.122 +		for (int y = 0; y < 144; y++)
  16.123 +		{
  16.124 +			int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip + gbBorderColumnSkip;
  16.125 +			u8 *dest  = (u8 *)pix + yLine * 3;
  16.126 +			for (register int x = 0; x < 160; x++)
  16.127 +			{
  16.128 +				gbSgbDraw24Bit(dest, color);
  16.129 +				dest += 3;
  16.130 +			}
  16.131 +		}
  16.132 +	}
  16.133 +	break;
  16.134 +	case 32:
  16.135 +	{
  16.136 +		for (int y = 0; y < 144; y++)
  16.137 +		{
  16.138 +			int	 yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 1) + gbBorderColumnSkip;
  16.139 +			u32 *dest  = (u32 *)pix + yLine;
  16.140 +			for (register int x = 0; x < 160; x++)
  16.141 +			{
  16.142 +				gbSgbDraw32Bit(dest++, color);
  16.143 +			}
  16.144 +		}
  16.145 +	}
  16.146 +	break;
  16.147 +	}
  16.148 +}
  16.149 +
  16.150 +void gbSgbRenderScreenToBuffer()
  16.151 +{
  16.152 +	u16 mapAddress = 0x9800;
  16.153 +
  16.154 +	if (register_LCDC & 0x08)
  16.155 +		mapAddress = 0x9c00;
  16.156 +
  16.157 +	u16 patternAddress = 0x8800;
  16.158 +
  16.159 +	int flag = 1;
  16.160 +
  16.161 +	if (register_LCDC & 0x10)
  16.162 +	{
  16.163 +		patternAddress = 0x8000;
  16.164 +		flag = 0;
  16.165 +	}
  16.166 +
  16.167 +	u8 *toAddress = gbSgbScreenBuffer;
  16.168 +
  16.169 +	for (int i = 0; i < 13; i++)
  16.170 +	{
  16.171 +		for (int j = 0; j < 20; j++)
  16.172 +		{
  16.173 +			int tile = gbReadMemoryQuick(mapAddress);
  16.174 +			mapAddress++;
  16.175 +
  16.176 +			if (flag)
  16.177 +			{
  16.178 +				if (tile > 127)
  16.179 +					tile -= 128;
  16.180 +				else
  16.181 +					tile += 128;
  16.182 +			}
  16.183 +			for (int k = 0; k < 16; k++)
  16.184 +				*toAddress++ = gbReadMemoryQuick(patternAddress + tile * 16 + k);
  16.185 +		}
  16.186 +		mapAddress += 12;
  16.187 +	}
  16.188 +}
  16.189 +
  16.190 +void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
  16.191 +{
  16.192 +	u16 *dest	= (u16 *)pix + ((y + 1) * (256 + 2)) + x;
  16.193 +	u8 * dest8	= (u8 *)pix + ((y * 256) + x) * 3;
  16.194 +	u32 *dest32 = (u32 *)pix + ((y + 1) * 257) + x;
  16.195 +
  16.196 +	u8 *tileAddress	 = &gbSgbBorderChar[tile * 32];
  16.197 +	u8 *tileAddress2 = &gbSgbBorderChar[tile * 32 + 16];
  16.198 +
  16.199 +	u8 l = 8;
  16.200 +
  16.201 +	u8 palette = ((attr >> 2) & 7);
  16.202 +
  16.203 +	if (palette < 4)
  16.204 +		palette += 4;
  16.205 +
  16.206 +	palette *= 16;
  16.207 +
  16.208 +	u8 xx = 0;
  16.209 +	u8 yy = 0;
  16.210 +
  16.211 +	int flipX = attr & 0x40;
  16.212 +	int flipY = attr & 0x80;
  16.213 +
  16.214 +	while (l > 0)
  16.215 +	{
  16.216 +		u8 mask = 0x80;
  16.217 +		u8 a	= *tileAddress++;
  16.218 +		u8 b	= *tileAddress++;
  16.219 +		u8 c	= *tileAddress2++;
  16.220 +		u8 d	= *tileAddress2++;
  16.221 +
  16.222 +		while (mask > 0)
  16.223 +		{
  16.224 +			u8 color = 0;
  16.225 +			if (a & mask)
  16.226 +				color++;
  16.227 +			if (b & mask)
  16.228 +				color += 2;
  16.229 +			if (c & mask)
  16.230 +				color += 4;
  16.231 +			if (d & mask)
  16.232 +				color += 8;
  16.233 +
  16.234 +			u8 xxx = xx;
  16.235 +			u8 yyy = yy;
  16.236 +
  16.237 +			if (flipX)
  16.238 +				xxx = 7 - xx;
  16.239 +			if (flipY)
  16.240 +				yyy = 7 - yy;
  16.241 +
  16.242 +			u8 realx = x + xxx;
  16.243 +			u8 realy = y + yyy;
  16.244 +
  16.245 +			u16 c = gbPalette[palette + color];
  16.246 +			if (!color)
  16.247 +				c = gbPalette[0];
  16.248 +			if ((realy < 40 || realy >= 184) || (realx < 48 || realx >= 208))
  16.249 +			{
  16.250 +				switch (systemColorDepth)
  16.251 +				{
  16.252 +				case 16:
  16.253 +					gbSgbDraw16Bit(dest + yyy * (256 + 2) + xxx, c);
  16.254 +					break;
  16.255 +				case 24:
  16.256 +					gbSgbDraw24Bit(dest8 + (yyy * 256 + xxx) * 3, c);
  16.257 +					break;
  16.258 +				case 32:
  16.259 +					gbSgbDraw32Bit(dest32 + yyy * (256 + 1) + xxx, c);
  16.260 +					break;
  16.261 +				}
  16.262 +			}
  16.263 +
  16.264 +			mask >>= 1;
  16.265 +
  16.266 +			xx++;
  16.267 +		}
  16.268 +		yy++;
  16.269 +		xx = 0;
  16.270 +		l--;
  16.271 +		mask = 0x80;
  16.272 +	}
  16.273 +}
  16.274 +
  16.275 +void gbSgbRenderBorder()
  16.276 +{
  16.277 +	if (gbBorderOn)
  16.278 +	{
  16.279 +		u8 *fromAddress = gbSgbBorder;
  16.280 +
  16.281 +		for (u8 y = 0; y < 28; y++)
  16.282 +		{
  16.283 +			for (u8 x = 0; x < 32; x++)
  16.284 +			{
  16.285 +				u8 tile = *fromAddress++;
  16.286 +				u8 attr = *fromAddress++;
  16.287 +
  16.288 +				gbSgbDrawBorderTile(x * 8, y * 8, tile, attr);
  16.289 +			}
  16.290 +		}
  16.291 +	}
  16.292 +}
  16.293 +
  16.294 +void gbSgbPicture()
  16.295 +{
  16.296 +	gbSgbRenderScreenToBuffer();
  16.297 +
  16.298 +	memcpy(gbSgbBorder, gbSgbScreenBuffer, 2048);
  16.299 +
  16.300 +	u16 *paletteAddr = (u16 *)&gbSgbScreenBuffer[2048];
  16.301 +
  16.302 +	for (int i = 64; i < 128; i++)
  16.303 +	{
  16.304 +		gbPalette[i] = READ16LE(paletteAddr++);
  16.305 +	}
  16.306 +
  16.307 +	gbSgbCGBSupport |= 4;
  16.308 +
  16.309 +	if (gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4)
  16.310 +	{
  16.311 +		gbBorderOn = 1;
  16.312 +		systemGbBorderOn();
  16.313 +	}
  16.314 +
  16.315 +	if (gbBorderOn && !gbSgbMask)
  16.316 +		gbSgbRenderBorder();
  16.317 +
  16.318 +	if (gbSgbMode && gbCgbMode && gbSgbCGBSupport > 4)
  16.319 +	{
  16.320 +		gbSgbCGBSupport = 0;
  16.321 +		gbSgbMode		= 2;
  16.322 +		gbSgbMask		= 0;
  16.323 +		gbSgbRenderBorder();
  16.324 +		gbReset();
  16.325 +	}
  16.326 +
  16.327 +	if (gbSgbCGBSupport > 4)
  16.328 +		gbSgbCGBSupport = 0;
  16.329 +}
  16.330 +
  16.331 +void gbSgbSetPalette(int a, int b, u16 *p)
  16.332 +{
  16.333 +	u16 bit00 = READ16LE(p++);
  16.334 +	int i;
  16.335 +
  16.336 +	for (i = 1; i < 4; i++)
  16.337 +	{
  16.338 +		gbPalette[a * 4 + i] = READ16LE(p++);
  16.339 +	}
  16.340 +
  16.341 +	for (i = 1; i < 4; i++)
  16.342 +	{
  16.343 +		gbPalette[b * 4 + i] = READ16LE(p++);
  16.344 +	}
  16.345 +
  16.346 +	gbPalette[0] = gbPalette[4] = gbPalette[8] = gbPalette[12] = bit00;
  16.347 +	if (gbBorderOn && !gbSgbMask)
  16.348 +		gbSgbRenderBorder();
  16.349 +}
  16.350 +
  16.351 +void gbSgbScpPalette()
  16.352 +{
  16.353 +	gbSgbRenderScreenToBuffer();
  16.354 +
  16.355 +	u16 *fromAddress = (u16 *)gbSgbScreenBuffer;
  16.356 +
  16.357 +	for (int i = 0; i < 512 * 4; i++)
  16.358 +	{
  16.359 +		gbSgbSCPPalette[i] = READ16LE(fromAddress++);
  16.360 +	}
  16.361 +}
  16.362 +
  16.363 +void gbSgbSetATF(int n)
  16.364 +{
  16.365 +	if (n < 0)
  16.366 +		n = 0;
  16.367 +	if (n > 44)
  16.368 +		n = 44;
  16.369 +	memcpy(gbSgbATF, &gbSgbATFList[n * 20 * 18], 20 * 18);
  16.370 +
  16.371 +	if (gbSgbPacket[1] & 0x40)
  16.372 +	{
  16.373 +		gbSgbMask = 0;
  16.374 +		if (gbBorderOn)
  16.375 +			gbSgbRenderBorder();
  16.376 +	}
  16.377 +}
  16.378 +
  16.379 +void gbSgbSetPalette()
  16.380 +{
  16.381 +	u16 pal = READ16LE((((u16 *)&gbSgbPacket[1]))) & 511;
  16.382 +	memcpy(&gbPalette[0], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16));
  16.383 +
  16.384 +	pal = READ16LE((((u16 *)&gbSgbPacket[3]))) & 511;
  16.385 +	memcpy(&gbPalette[4], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16));
  16.386 +
  16.387 +	pal = READ16LE((((u16 *)&gbSgbPacket[5]))) & 511;
  16.388 +	memcpy(&gbPalette[8], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16));
  16.389 +
  16.390 +	pal = READ16LE((((u16 *)&gbSgbPacket[7]))) & 511;
  16.391 +	memcpy(&gbPalette[12], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16));
  16.392 +
  16.393 +	u8 atf = gbSgbPacket[9];
  16.394 +
  16.395 +	if (atf & 0x80)
  16.396 +	{
  16.397 +		gbSgbSetATF(atf & 0x3f);
  16.398 +	}
  16.399 +
  16.400 +	if (atf & 0x40)
  16.401 +	{
  16.402 +		gbSgbMask = 0;
  16.403 +		if (gbBorderOn)
  16.404 +			gbSgbRenderBorder();
  16.405 +	}
  16.406 +}
  16.407 +
  16.408 +void gbSgbAttributeBlock()
  16.409 +{
  16.410 +	u8 *fromAddress = &gbSgbPacket[1];
  16.411 +
  16.412 +	u8 nDataSet = *fromAddress++;
  16.413 +	if (nDataSet > 12)
  16.414 +		nDataSet = 12;
  16.415 +	if (nDataSet == 0)
  16.416 +		nDataSet = 1;
  16.417 +
  16.418 +	while (nDataSet)
  16.419 +	{
  16.420 +		u8 controlCode		  = (*fromAddress++) & 7;
  16.421 +		u8 paletteDesignation = (*fromAddress++) & 0x3f;
  16.422 +		u8 startH = (*fromAddress++) & 0x1f;
  16.423 +		u8 startV = (*fromAddress++) & 0x1f;
  16.424 +		u8 endH	  = (*fromAddress++) & 0x1f;
  16.425 +		u8 endV	  = (*fromAddress++) & 0x1f;
  16.426 +
  16.427 +		u8 *toAddress = gbSgbATF;
  16.428 +
  16.429 +		for (u8 y = 0; y < 18; y++)
  16.430 +		{
  16.431 +			for (u8 x = 0; x < 20; x++)
  16.432 +			{
  16.433 +				if (x < startH || y < startV ||
  16.434 +				    x > endH || y > endV)
  16.435 +				{
  16.436 +					// outside
  16.437 +					if (controlCode & 0x04)
  16.438 +						*toAddress = (paletteDesignation >> 4) & 0x03;
  16.439 +				}
  16.440 +				else if (x > startH && x < endH &&
  16.441 +				         y > startV && y < endV)
  16.442 +				{
  16.443 +					// inside
  16.444 +					if (controlCode & 0x01)
  16.445 +						*toAddress = paletteDesignation & 0x03;
  16.446 +				}
  16.447 +				else
  16.448 +				{
  16.449 +					// surrounding line
  16.450 +					if (controlCode & 0x02)
  16.451 +						*toAddress = (paletteDesignation >> 2) & 0x03;
  16.452 +					else if (controlCode == 0x01)
  16.453 +						*toAddress = paletteDesignation & 0x03;
  16.454 +				}
  16.455 +				toAddress++;
  16.456 +			}
  16.457 +		}
  16.458 +		nDataSet--;
  16.459 +	}
  16.460 +}
  16.461 +
  16.462 +void gbSgbSetColumnPalette(u8 col, u8 p)
  16.463 +{
  16.464 +	//  if(col < 0)
  16.465 +	//    col = 0;
  16.466 +	if (col > 19)
  16.467 +		col = 19;
  16.468 +
  16.469 +	p &= 3;
  16.470 +
  16.471 +	u8 *toAddress = &gbSgbATF[col];
  16.472 +
  16.473 +	for (u8 y = 0; y < 18; y++)
  16.474 +	{
  16.475 +		*toAddress = p;
  16.476 +		toAddress += 20;
  16.477 +	}
  16.478 +}
  16.479 +
  16.480 +void gbSgbSetRowPalette(u8 row, u8 p)
  16.481 +{
  16.482 +	//  if(row < 0)
  16.483 +	//    row = 0;
  16.484 +	if (row > 17)
  16.485 +		row = 17;
  16.486 +
  16.487 +	p &= 3;
  16.488 +
  16.489 +	u8 *toAddress = &gbSgbATF[row * 20];
  16.490 +
  16.491 +	for (u8 x = 0; x < 20; x++)
  16.492 +	{
  16.493 +		*toAddress++ = p;
  16.494 +	}
  16.495 +}
  16.496 +
  16.497 +void gbSgbAttributeDivide()
  16.498 +{
  16.499 +	u8 control = gbSgbPacket[1];
  16.500 +	u8 coord   = gbSgbPacket[2];
  16.501 +	u8 colorBR = control & 3;
  16.502 +	u8 colorAL = (control >> 2) & 3;
  16.503 +	u8 colorOL = (control >> 4) & 3;
  16.504 +
  16.505 +	if (control & 0x40)
  16.506 +	{
  16.507 +		if (coord > 17)
  16.508 +			coord = 17;
  16.509 +
  16.510 +		for (u8 i = 0; i < 18; i++)
  16.511 +		{
  16.512 +			if (i < coord)
  16.513 +				gbSgbSetRowPalette(i, colorAL);
  16.514 +			else if (i > coord)
  16.515 +				gbSgbSetRowPalette(i, colorBR);
  16.516 +			else
  16.517 +				gbSgbSetRowPalette(i, colorOL);
  16.518 +		}
  16.519 +	}
  16.520 +	else
  16.521 +	{
  16.522 +		if (coord > 19)
  16.523 +			coord = 19;
  16.524 +
  16.525 +		for (u8 i = 0; i < 20; i++)
  16.526 +		{
  16.527 +			if (i < coord)
  16.528 +				gbSgbSetColumnPalette(i, colorAL);
  16.529 +			else if (i > coord)
  16.530 +				gbSgbSetColumnPalette(i, colorBR);
  16.531 +			else
  16.532 +				gbSgbSetColumnPalette(i, colorOL);
  16.533 +		}
  16.534 +	}
  16.535 +}
  16.536 +
  16.537 +void gbSgbAttributeLine()
  16.538 +{
  16.539 +	u8 *fromAddress = &gbSgbPacket[1];
  16.540 +
  16.541 +	u8 nDataSet = *fromAddress++;
  16.542 +
  16.543 +	if (nDataSet > 0x6e)
  16.544 +		nDataSet = 0x6e;
  16.545 +
  16.546 +	while (nDataSet)
  16.547 +	{
  16.548 +		u8 line = *fromAddress++;
  16.549 +		u8 num	= line & 0x1f;
  16.550 +		u8 pal	= (line >> 5) & 0x03;
  16.551 +		if (line & 0x80)
  16.552 +		{
  16.553 +			if (num > 17)
  16.554 +				num = 17;
  16.555 +			gbSgbSetRowPalette(num, pal);
  16.556 +		}
  16.557 +		else
  16.558 +		{
  16.559 +			if (num > 19)
  16.560 +				num = 19;
  16.561 +			gbSgbSetColumnPalette(num, pal);
  16.562 +		}
  16.563 +		nDataSet--;
  16.564 +	}
  16.565 +}
  16.566 +
  16.567 +void gbSgbAttributeCharacter()
  16.568 +{
  16.569 +	u8	startH	 = gbSgbPacket[1] & 0x1f;
  16.570 +	u8	startV	 = gbSgbPacket[2] & 0x1f;
  16.571 +	int nDataSet = READ16LE(((u16 *)&gbSgbPacket[3]));
  16.572 +	int style	 = gbSgbPacket[5] & 1;
  16.573 +	if (startH > 19)
  16.574 +		startH = 19;
  16.575 +	if (startV > 17)
  16.576 +		startV = 17;
  16.577 +
  16.578 +	u8	s = 6;
  16.579 +	u8 *fromAddress = &gbSgbPacket[6];
  16.580 +	u8	v = *fromAddress++;
  16.581 +
  16.582 +	if (style)
  16.583 +	{
  16.584 +		while (nDataSet)
  16.585 +		{
  16.586 +			u8 p = (v >> s) & 3;
  16.587 +			gbSgbATF[startV * 20 + startH] = p;
  16.588 +			startV++;
  16.589 +			if (startV == 18)
  16.590 +			{
  16.591 +				startV = 0;
  16.592 +				startH++;
  16.593 +				if (startH == 20)
  16.594 +					break;
  16.595 +			}
  16.596 +
  16.597 +			if (s)
  16.598 +				s -= 2;
  16.599 +			else
  16.600 +			{
  16.601 +				s = 6;
  16.602 +				v = *fromAddress++;
  16.603 +				nDataSet--;
  16.604 +			}
  16.605 +		}
  16.606 +	}
  16.607 +	else
  16.608 +	{
  16.609 +		while (nDataSet)
  16.610 +		{
  16.611 +			u8 p = (v >> s) & 3;
  16.612 +			gbSgbATF[startV * 20 + startH] = p;
  16.613 +			startH++;
  16.614 +			if (startH == 20)
  16.615 +			{
  16.616 +				startH = 0;
  16.617 +				startV++;
  16.618 +				if (startV == 18)
  16.619 +					break;
  16.620 +			}
  16.621 +
  16.622 +			if (s)
  16.623 +				s -= 2;
  16.624 +			else
  16.625 +			{
  16.626 +				s = 6;
  16.627 +				v = *fromAddress++;
  16.628 +				nDataSet--;
  16.629 +			}
  16.630 +		}
  16.631 +	}
  16.632 +}
  16.633 +
  16.634 +void gbSgbSetATFList()
  16.635 +{
  16.636 +	gbSgbRenderScreenToBuffer();
  16.637 +
  16.638 +	u8 *fromAddress = gbSgbScreenBuffer;
  16.639 +	u8 *toAddress	= gbSgbATFList;
  16.640 +
  16.641 +	for (int i = 0; i < 45; i++)
  16.642 +	{
  16.643 +		for (int j = 0; j < 90; j++)
  16.644 +		{
  16.645 +			u8 v = *fromAddress++;
  16.646 +			u8 s = 6;
  16.647 +			if (i == 2)
  16.648 +				s = 6;
  16.649 +			for (int k = 0; k < 4; k++)
  16.650 +			{
  16.651 +				*toAddress++ = (v >> s) & 0x03;
  16.652 +				s -= 2;
  16.653 +			}
  16.654 +		}
  16.655 +	}
  16.656 +}
  16.657 +
  16.658 +void gbSgbMaskEnable()
  16.659 +{
  16.660 +	int gbSgbMaskFlag = gbSgbPacket[1] & 3;
  16.661 +
  16.662 +	gbSgbMask = gbSgbMaskFlag;
  16.663 +
  16.664 +	switch (gbSgbMaskFlag)
  16.665 +	{
  16.666 +	case 1:
  16.667 +		break;
  16.668 +	case 2:
  16.669 +		gbSgbFillScreen(0x0000);
  16.670 +		//    memset(&gbPalette[0], 0, 128*sizeof(u16));
  16.671 +		break;
  16.672 +	case 3:
  16.673 +		gbSgbFillScreen(gbPalette[0]);
  16.674 +		break;
  16.675 +	}
  16.676 +	if (!gbSgbMask)
  16.677 +	{
  16.678 +		if (gbBorderOn)
  16.679 +			gbSgbRenderBorder();
  16.680 +	}
  16.681 +}
  16.682 +
  16.683 +void gbSgbChrTransfer()
  16.684 +{
  16.685 +	gbSgbRenderScreenToBuffer();
  16.686 +
  16.687 +	int address = (gbSgbPacket[1] & 1) * (128 * 32);
  16.688 +
  16.689 +	if (gbSgbPacket[1] & 1)
  16.690 +		gbSgbCGBSupport |= 2;
  16.691 +	else
  16.692 +		gbSgbCGBSupport |= 1;
  16.693 +
  16.694 +	memcpy(&gbSgbBorderChar[address], gbSgbScreenBuffer, 128 * 32);
  16.695 +
  16.696 +	if (gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4)
  16.697 +	{
  16.698 +		gbBorderOn = 1;
  16.699 +		systemGbBorderOn();
  16.700 +	}
  16.701 +
  16.702 +	if (gbBorderOn && !gbSgbMask)
  16.703 +		gbSgbRenderBorder();
  16.704 +
  16.705 +	if (gbSgbMode && gbCgbMode && gbSgbCGBSupport == 7)
  16.706 +	{
  16.707 +		gbSgbCGBSupport = 0;
  16.708 +		gbSgbMode		= 2;
  16.709 +		gbSgbMask		= 0;
  16.710 +		gbSgbRenderBorder();
  16.711 +		gbReset();
  16.712 +	}
  16.713 +
  16.714 +	if (gbSgbCGBSupport > 4)
  16.715 +		gbSgbCGBSupport = 0;
  16.716 +}
  16.717 +
  16.718 +void gbSgbMultiRequest()
  16.719 +{
  16.720 +	if (gbSgbPacket[1] & 1)
  16.721 +	{
  16.722 +		gbSgbMultiplayer = 1;
  16.723 +		if (gbSgbPacket[1] & 2)
  16.724 +			gbSgbFourPlayers = 1;
  16.725 +		else
  16.726 +			gbSgbFourPlayers = 0;
  16.727 +		gbSgbNextController = 0x0e;
  16.728 +	}
  16.729 +	else
  16.730 +	{
  16.731 +		gbSgbFourPlayers	= 0;
  16.732 +		gbSgbMultiplayer	= 0;
  16.733 +		gbSgbNextController = 0x0f;
  16.734 +	}
  16.735 +}
  16.736 +
  16.737 +void gbSgbCommand()
  16.738 +{
  16.739 +	int command = gbSgbPacket[0] >> 3;
  16.740 +	//  int nPacket = gbSgbPacket[0] & 7;
  16.741 +
  16.742 +	switch (command)
  16.743 +	{
  16.744 +	case 0x00:
  16.745 +		gbSgbSetPalette(0, 1, (u16 *)&gbSgbPacket[1]);
  16.746 +		break;
  16.747 +	case 0x01:
  16.748 +		gbSgbSetPalette(2, 3, (u16 *)&gbSgbPacket[1]);
  16.749 +		break;
  16.750 +	case 0x02:
  16.751 +		gbSgbSetPalette(0, 3, (u16 *)&gbSgbPacket[1]);
  16.752 +		break;
  16.753 +	case 0x03:
  16.754 +		gbSgbSetPalette(1, 2, (u16 *)&gbSgbPacket[1]);
  16.755 +		break;
  16.756 +	case 0x04:
  16.757 +		gbSgbAttributeBlock();
  16.758 +		break;
  16.759 +	case 0x05:
  16.760 +		gbSgbAttributeLine();
  16.761 +		break;
  16.762 +	case 0x06:
  16.763 +		gbSgbAttributeDivide();
  16.764 +		break;
  16.765 +	case 0x07:
  16.766 +		gbSgbAttributeCharacter();
  16.767 +		break;
  16.768 +	case 0x0a:
  16.769 +		gbSgbSetPalette();
  16.770 +		break;
  16.771 +	case 0x0b:
  16.772 +		gbSgbScpPalette();
  16.773 +		break;
  16.774 +	case 0x11:
  16.775 +		gbSgbMultiRequest();
  16.776 +		break;
  16.777 +	case 0x13:
  16.778 +		gbSgbChrTransfer();
  16.779 +		break;
  16.780 +	case 0x14:
  16.781 +		gbSgbPicture();
  16.782 +		break;
  16.783 +	case 0x15:
  16.784 +		gbSgbSetATFList();
  16.785 +		break;
  16.786 +	case 0x16:
  16.787 +		gbSgbSetATF(gbSgbPacket[1] & 0x3f);
  16.788 +		break;
  16.789 +	case 0x17:
  16.790 +		gbSgbMaskEnable();
  16.791 +		break;
  16.792 +	}
  16.793 +}
  16.794 +
  16.795 +void gbSgbResetPacketState()
  16.796 +{
  16.797 +	gbSgbPacketState   = GBSGB_NONE;
  16.798 +	gbSgbPacketTimeout = 0;
  16.799 +}
  16.800 +
  16.801 +void gbSgbDoBitTransfer(u8 value)
  16.802 +{
  16.803 +	value = value & 0x30;
  16.804 +	switch (gbSgbPacketState)
  16.805 +	{
  16.806 +	case GBSGB_NONE:
  16.807 +		if (value == 0)
  16.808 +		{
  16.809 +			gbSgbPacketState   = GBSGB_RESET;
  16.810 +			gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
  16.811 +		}
  16.812 +		else if (value == 0x30)
  16.813 +		{
  16.814 +			if (gbSgbMultiplayer)
  16.815 +			{
  16.816 +				if ((gbSgbReadingController & 7) == 7)
  16.817 +				{
  16.818 +					gbSgbReadingController = 0;
  16.819 +					if (gbSgbMultiplayer)
  16.820 +					{
  16.821 +						gbSgbNextController--;
  16.822 +						if (gbSgbFourPlayers)
  16.823 +						{
  16.824 +							if (gbSgbNextController == 0x0b)
  16.825 +								gbSgbNextController = 0x0f;
  16.826 +						}
  16.827 +						else
  16.828 +						{
  16.829 +							if (gbSgbNextController == 0x0d)
  16.830 +								gbSgbNextController = 0x0f;
  16.831 +						}
  16.832 +					}
  16.833 +				}
  16.834 +				else
  16.835 +				{
  16.836 +					gbSgbReadingController &= 3;
  16.837 +				}
  16.838 +			}
  16.839 +			gbSgbPacketTimeout = 0;
  16.840 +		}
  16.841 +		else
  16.842 +		{
  16.843 +			if (value == 0x10)
  16.844 +				gbSgbReadingController |= 0x2;
  16.845 +			else if (value == 0x20)
  16.846 +				gbSgbReadingController |= 0x01;
  16.847 +			gbSgbPacketTimeout = 0;
  16.848 +		}
  16.849 +		gbSgbPacketTimeout = 0;
  16.850 +		break;
  16.851 +	case GBSGB_RESET:
  16.852 +		if (value == 0x30)
  16.853 +		{
  16.854 +			gbSgbPacketState   = GBSGB_PACKET_TRANSMIT;
  16.855 +			gbSgbPacketByte	   = 0;
  16.856 +			gbSgbPacketNBits   = 0;
  16.857 +			gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
  16.858 +		}
  16.859 +		else if (value == 0x00)
  16.860 +		{
  16.861 +			gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
  16.862 +			gbSgbPacketState   = GBSGB_RESET;
  16.863 +		}
  16.864 +		else
  16.865 +		{
  16.866 +			gbSgbPacketState   = GBSGB_NONE;
  16.867 +			gbSgbPacketTimeout = 0;
  16.868 +		}
  16.869 +		break;
  16.870 +	case GBSGB_PACKET_TRANSMIT:
  16.871 +		if (value == 0)
  16.872 +		{
  16.873 +			gbSgbPacketState   = GBSGB_RESET;
  16.874 +			gbSgbPacketTimeout = 0;
  16.875 +		}
  16.876 +		else if (value == 0x30)
  16.877 +		{
  16.878 +			if (gbSgbPacketNBits == 128)
  16.879 +			{
  16.880 +				gbSgbPacketNBits = 0;
  16.881 +				gbSgbPacketByte	 = 0;
  16.882 +				gbSgbPacketNumber++;
  16.883 +				gbSgbPacketTimeout = 0;
  16.884 +				if (gbSgbPacketNumber == (gbSgbPacket[0] & 7))
  16.885 +				{
  16.886 +					gbSgbCommand();
  16.887 +					gbSgbPacketNumber  = 0;
  16.888 +					gbSgbPacketState   = GBSGB_NONE;
  16.889 +					gbSgbPacketTimeout = 0;
  16.890 +				}
  16.891 +			}
  16.892 +			else
  16.893 +			{
  16.894 +				if (gbSgbPacketNBits < 128)
  16.895 +				{
  16.896 +					gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] >>= 1;
  16.897 +					gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte]  |= gbSgbBit;
  16.898 +					gbSgbPacketNBits++;
  16.899 +					if (!(gbSgbPacketNBits & 7))
  16.900 +					{
  16.901 +						gbSgbPacketByte++;
  16.902 +					}
  16.903 +					gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
  16.904 +				}
  16.905 +			}
  16.906 +		}
  16.907 +		else
  16.908 +		{
  16.909 +			if (value == 0x20)
  16.910 +				gbSgbBit = 0x00;
  16.911 +			else
  16.912 +				gbSgbBit = 0x80;
  16.913 +			gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
  16.914 +		}
  16.915 +		gbSgbReadingController = 0;
  16.916 +		break;
  16.917 +	default:
  16.918 +		gbSgbPacketState   = GBSGB_NONE;
  16.919 +		gbSgbPacketTimeout = 0;
  16.920 +		break;
  16.921 +	}
  16.922 +}
  16.923 +
  16.924 +variable_desc gbSgbSaveStruct[] = {
  16.925 +	{ &gbSgbMask,			   sizeof(int32) },
  16.926 +	{ &gbSgbPacketState,	   sizeof(int32) },
  16.927 +	{ &gbSgbBit,			   sizeof(int32) },
  16.928 +	{ &gbSgbPacketNBits,	   sizeof(int32) },
  16.929 +	{ &gbSgbPacketByte,		   sizeof(int32) },
  16.930 +	{ &gbSgbPacketNumber,	   sizeof(int32) },
  16.931 +	{ &gbSgbMultiplayer,	   sizeof(int32) },
  16.932 +	{ &gbSgbNextController,	   sizeof(u8)	 },
  16.933 +	{ &gbSgbReadingController, sizeof(u8)	 },
  16.934 +	{ NULL,					   0			 }
  16.935 +};
  16.936 +
  16.937 +variable_desc gbSgbSaveStructV3[] = {
  16.938 +	{ &gbSgbMask,			   sizeof(int32) },
  16.939 +	{ &gbSgbPacketState,	   sizeof(int32) },
  16.940 +	{ &gbSgbBit,			   sizeof(int32) },
  16.941 +	{ &gbSgbPacketNBits,	   sizeof(int32) },
  16.942 +	{ &gbSgbPacketByte,		   sizeof(int32) },
  16.943 +	{ &gbSgbPacketNumber,	   sizeof(int32) },
  16.944 +	{ &gbSgbMultiplayer,	   sizeof(int32) },
  16.945 +	{ &gbSgbNextController,	   sizeof(u8)	 },
  16.946 +	{ &gbSgbReadingController, sizeof(u8)	 },
  16.947 +	{ &gbSgbFourPlayers,	   sizeof(int32) },
  16.948 +	{ NULL,					   0			 }
  16.949 +};
  16.950 +
  16.951 +void gbSgbSaveGame(gzFile gzFile)
  16.952 +{
  16.953 +	utilWriteData(gzFile, gbSgbSaveStructV3);
  16.954 +
  16.955 +	utilGzWrite(gzFile, gbSgbBorder, 2048);
  16.956 +	utilGzWrite(gzFile, gbSgbBorderChar, 32 * 256);
  16.957 +
  16.958 +	utilGzWrite(gzFile, gbSgbPacket, 16 * 7);
  16.959 +
  16.960 +	utilGzWrite(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16));
  16.961 +	utilGzWrite(gzFile, gbSgbATF, 20 * 18);
  16.962 +	utilGzWrite(gzFile, gbSgbATFList, 45 * 20 * 18);
  16.963 +
  16.964 +	utilGzWrite(gzFile, gbSgbScreenBuffer, 4160);
  16.965 +	utilGzWrite(gzFile, &gbSgbMode, sizeof(gbSgbMode));
  16.966 +	utilGzWrite(gzFile, &gbSgbCGBSupport, sizeof(gbSgbCGBSupport));
  16.967 +	utilGzWrite(gzFile, &gbSgbPacketTimeout, sizeof(gbSgbPacketTimeout));
  16.968 +}
  16.969 +
  16.970 +void gbSgbReadGame(gzFile gzFile, int version)
  16.971 +{
  16.972 +	if (version >= 3)
  16.973 +		utilReadData(gzFile, gbSgbSaveStructV3);
  16.974 +	else
  16.975 +	{
  16.976 +		utilReadData(gzFile, gbSgbSaveStruct);
  16.977 +		gbSgbFourPlayers = 0;
  16.978 +	}
  16.979 +
  16.980 +	if (version >= 8)
  16.981 +	{
  16.982 +		utilGzRead(gzFile, gbSgbBorder, 2048);
  16.983 +		utilGzRead(gzFile, gbSgbBorderChar, 32 * 256);
  16.984 +	}
  16.985 +
  16.986 +	utilGzRead(gzFile, gbSgbPacket, 16 * 7);
  16.987 +
  16.988 +	utilGzRead(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16));
  16.989 +	utilGzRead(gzFile, gbSgbATF, 20 * 18);
  16.990 +	utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18);
  16.991 +
  16.992 +	if (version >= 11)
  16.993 +	{
  16.994 +		utilGzRead(gzFile, gbSgbScreenBuffer, 4160);
  16.995 +		utilGzRead(gzFile, &gbSgbMode, sizeof(gbSgbMode));
  16.996 +		utilGzRead(gzFile, &gbSgbCGBSupport, sizeof(gbSgbCGBSupport));
  16.997 +		utilGzRead(gzFile, &gbSgbPacketTimeout, sizeof(gbSgbPacketTimeout));
  16.998 +	}
  16.999 +}
 16.1000 +
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/gb/gbSGB.h	Sat Mar 03 11:44:47 2012 -0600
    17.3 @@ -0,0 +1,30 @@
    17.4 +#ifndef VBA_GB_SGB_H
    17.5 +#define VBA_GB_SGB_H
    17.6 +
    17.7 +#if _MSC_VER > 1000
    17.8 +#pragma once
    17.9 +#endif // _MSC_VER > 1000
   17.10 +
   17.11 +#include "zlib.h"
   17.12 +#include "../Port.h"
   17.13 +
   17.14 +void gbSgbInit();
   17.15 +void gbSgbShutdown();
   17.16 +void gbSgbCommand();
   17.17 +void gbSgbResetPacketState();
   17.18 +void gbSgbReset();
   17.19 +void gbSgbDoBitTransfer(u8);
   17.20 +void gbSgbSaveGame(gzFile);
   17.21 +void gbSgbReadGame(gzFile, int version);
   17.22 +void gbSgbRenderBorder();
   17.23 +
   17.24 +extern u8    gbSgbATF[20*18];
   17.25 +extern int32 gbSgbMode;
   17.26 +extern int32 gbSgbMask;
   17.27 +extern int32 gbSgbMultiplayer;
   17.28 +extern u8    gbSgbNextController;
   17.29 +extern int32 gbSgbPacketTimeout;
   17.30 +extern u8    gbSgbReadingController;
   17.31 +extern int32 gbSgbFourPlayers;
   17.32 +
   17.33 +#endif // VBA_GB_SGB_H
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/gb/gbSound.cpp	Sat Mar 03 11:44:47 2012 -0600
    18.3 @@ -0,0 +1,1139 @@
    18.4 +#ifdef WIN32
    18.5 +#   include "../win32/stdafx.h"
    18.6 +#   include "../win32/VBA.h"
    18.7 +#endif
    18.8 +
    18.9 +#include <cstring>
   18.10 +#include <cassert>
   18.11 +
   18.12 +#include "../common/System.h"
   18.13 +#include "../common/Util.h"
   18.14 +//#include "../Blip_Buffer.h"
   18.15 +#include "gbGlobals.h"
   18.16 +#include "gbSound.h"
   18.17 +
   18.18 +#ifndef countof
   18.19 +#define countof(a)  (sizeof(a) / sizeof(a[0]))
   18.20 +#endif
   18.21 +
   18.22 +extern u8	 soundBuffer[6][735];
   18.23 +extern u16	 soundFinalWave[1470];
   18.24 +extern u16	 soundFrameSound[735 * 30 * 2];
   18.25 +extern int32 soundVolume;
   18.26 +
   18.27 +soundtick_t GB_USE_TICKS_AS = 24; // (1048576.0/44100.0); // FIXME: (4194304.0/70224.0)(fps) vs 60.0fps?
   18.28 +
   18.29 +#define SOUND_MAGIC   0x60000000
   18.30 +#define SOUND_MAGIC_2 0x30000000
   18.31 +#define NOISE_MAGIC   (2097152.0 / 44100.0)
   18.32 +
   18.33 +extern int32 speed;
   18.34 +
   18.35 +extern u8 soundWavePattern[4][32];
   18.36 +
   18.37 +extern u32		   soundBufferLen;
   18.38 +extern u32		   soundBufferTotalLen;
   18.39 +extern int32	   soundQuality;
   18.40 +extern int32	   soundPaused;
   18.41 +extern int32	   soundPlay;
   18.42 +extern soundtick_t soundTicks;
   18.43 +extern soundtick_t SOUND_CLOCK_TICKS;
   18.44 +extern u32		   soundNextPosition;
   18.45 +
   18.46 +extern int32 soundLevel1;
   18.47 +extern int32 soundLevel2;
   18.48 +extern int32 soundBalance;
   18.49 +extern int32 soundMasterOn;
   18.50 +extern u32	 soundIndex;
   18.51 +extern u32	 soundBufferIndex;
   18.52 +extern int32 soundFrameSoundWritten;
   18.53 +int32		 soundVIN = 0;
   18.54 +extern int32 soundDebug;
   18.55 +
   18.56 +extern int32 sound1On;
   18.57 +extern int32 sound1ATL;
   18.58 +extern int32 sound1Skip;
   18.59 +extern int32 sound1Index;
   18.60 +extern int32 sound1Continue;
   18.61 +extern int32 sound1EnvelopeVolume;
   18.62 +extern int32 sound1EnvelopeATL;
   18.63 +extern int32 sound1EnvelopeUpDown;
   18.64 +extern int32 sound1EnvelopeATLReload;
   18.65 +extern int32 sound1SweepATL;
   18.66 +extern int32 sound1SweepATLReload;
   18.67 +extern int32 sound1SweepSteps;
   18.68 +extern int32 sound1SweepUpDown;
   18.69 +extern int32 sound1SweepStep;
   18.70 +extern u8 *	 sound1Wave;
   18.71 +
   18.72 +extern int32 sound2On;
   18.73 +extern int32 sound2ATL;
   18.74 +extern int32 sound2Skip;
   18.75 +extern int32 sound2Index;
   18.76 +extern int32 sound2Continue;
   18.77 +extern int32 sound2EnvelopeVolume;
   18.78 +extern int32 sound2EnvelopeATL;
   18.79 +extern int32 sound2EnvelopeUpDown;
   18.80 +extern int32 sound2EnvelopeATLReload;
   18.81 +extern u8 *	 sound2Wave;
   18.82 +
   18.83 +extern int32 sound3On;
   18.84 +extern int32 sound3ATL;
   18.85 +extern int32 sound3Skip;
   18.86 +extern int32 sound3Index;
   18.87 +extern int32 sound3Continue;
   18.88 +extern int32 sound3OutputLevel;
   18.89 +extern int32 sound3Last;
   18.90 +
   18.91 +extern int32 sound4On;
   18.92 +extern int32 sound4Clock;
   18.93 +extern int32 sound4ATL;
   18.94 +extern int32 sound4Skip;
   18.95 +extern int32 sound4Index;
   18.96 +extern int32 sound4ShiftRight;
   18.97 +extern int32 sound4ShiftSkip;
   18.98 +extern int32 sound4ShiftIndex;
   18.99 +extern int32 sound4NSteps;
  18.100 +extern int32 sound4CountDown;
  18.101 +extern int32 sound4Continue;
  18.102 +extern int32 sound4EnvelopeVolume;
  18.103 +extern int32 sound4EnvelopeATL;
  18.104 +extern int32 sound4EnvelopeUpDown;
  18.105 +extern int32 sound4EnvelopeATLReload;
  18.106 +
  18.107 +extern int32 soundEnableFlag;
  18.108 +extern int32 soundMutedFlag;
  18.109 +
  18.110 +extern int32 soundFreqRatio[8];
  18.111 +extern int32 soundShiftClock[16];
  18.112 +
  18.113 +extern s16	 soundFilter[4000];
  18.114 +extern s16	 soundLeft[5];
  18.115 +extern s16	 soundRight[5];
  18.116 +extern int32 soundEchoIndex;
  18.117 +extern bool8 soundEcho;
  18.118 +extern bool8 soundLowPass;
  18.119 +extern bool8 soundReverse;
  18.120 +extern bool8 soundOffFlag;
  18.121 +
  18.122 +bool8 gbDigitalSound = false;
  18.123 +
  18.124 +void gbSoundEvent(register u16 address, register int data)
  18.125 +{
  18.126 +	int freq = 0;
  18.127 +
  18.128 +	gbMemory[address] = data;
  18.129 +
  18.130 +#ifndef FINAL_VERSION
  18.131 +	if (soundDebug)
  18.132 +	{
  18.133 +		// don't translate. debug only
  18.134 +		log("Sound event: %08lx %02x\n", address, data);
  18.135 +	}
  18.136 +#endif
  18.137 +	switch (address)
  18.138 +	{
  18.139 +	case NR10:
  18.140 +		sound1SweepATL	  = sound1SweepATLReload = 344 * ((data >> 4) & 7);
  18.141 +		sound1SweepSteps  = data & 7;
  18.142 +		sound1SweepUpDown = data & 0x08;
  18.143 +		sound1SweepStep	  = 0;
  18.144 +		break;
  18.145 +	case NR11:
  18.146 +		sound1Wave = soundWavePattern[data >> 6];
  18.147 +		sound1ATL  = 172 * (64 - (data & 0x3f));
  18.148 +		break;
  18.149 +	case NR12:
  18.150 +		sound1EnvelopeVolume	= data >> 4;
  18.151 +		sound1EnvelopeUpDown	= data & 0x08;
  18.152 +		sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (data & 7);
  18.153 +		break;
  18.154 +	case NR13:
  18.155 +		freq	  = (((int)(gbMemory[NR14] & 7)) << 8) | data;
  18.156 +		sound1ATL = 172 * (64 - (gbMemory[NR11] & 0x3f));
  18.157 +		freq	  = 2048 - freq;
  18.158 +		if (freq)
  18.159 +		{
  18.160 +			sound1Skip = SOUND_MAGIC / freq;
  18.161 +		}
  18.162 +		else
  18.163 +			sound1Skip = 0;
  18.164 +		break;
  18.165 +	case NR14:
  18.166 +		freq = (((int)(data & 7) << 8) | gbMemory[NR13]);
  18.167 +		freq = 2048 - freq;
  18.168 +		sound1ATL	   = 172 * (64 - (gbMemory[NR11] & 0x3f));
  18.169 +		sound1Continue = data & 0x40;
  18.170 +		if (freq)
  18.171 +		{
  18.172 +			sound1Skip = SOUND_MAGIC / freq;
  18.173 +		}
  18.174 +		else
  18.175 +			sound1Skip = 0;
  18.176 +		if (data & 0x80)
  18.177 +		{
  18.178 +			gbMemory[NR52]		|= 1;
  18.179 +			sound1EnvelopeVolume = gbMemory[NR12] >> 4;
  18.180 +			sound1EnvelopeUpDown = gbMemory[NR12] & 0x08;
  18.181 +			sound1ATL = 172 * (64 - (gbMemory[NR11] & 0x3f));
  18.182 +			sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (gbMemory[NR12] & 7);
  18.183 +			sound1SweepATL			= sound1SweepATLReload = 344 * ((gbMemory[NR10] >> 4) & 7);
  18.184 +			sound1SweepSteps		= gbMemory[NR10] & 7;
  18.185 +			sound1SweepUpDown		= gbMemory[NR10] & 0x08;
  18.186 +			sound1SweepStep			= 0;
  18.187 +
  18.188 +			sound1Index = 0;
  18.189 +			sound1On	= 1;
  18.190 +		}
  18.191 +		break;
  18.192 +	case NR21:
  18.193 +		sound2Wave = soundWavePattern[data >> 6];
  18.194 +		sound2ATL  = 172 * (64 - (data & 0x3f));
  18.195 +		break;
  18.196 +	case NR22:
  18.197 +		sound2EnvelopeVolume	= data >> 4;
  18.198 +		sound2EnvelopeUpDown	= data & 0x08;
  18.199 +		sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (data & 7);
  18.200 +		break;
  18.201 +	case NR23:
  18.202 +		freq	  = (((int)(gbMemory[NR24] & 7)) << 8) | data;
  18.203 +		sound2ATL = 172 * (64 - (gbMemory[NR21] & 0x3f));
  18.204 +		freq	  = 2048 - freq;
  18.205 +		if (freq)
  18.206 +		{
  18.207 +			sound2Skip = SOUND_MAGIC / freq;
  18.208 +		}
  18.209 +		else
  18.210 +			sound2Skip = 0;
  18.211 +		break;
  18.212 +	case NR24:
  18.213 +		freq = (((int)(data & 7) << 8) | gbMemory[NR23]);
  18.214 +		freq = 2048 - freq;
  18.215 +		sound2ATL	   = 172 * (64 - (gbMemory[NR21] & 0x3f));
  18.216 +		sound2Continue = data & 0x40;
  18.217 +		if (freq)
  18.218 +		{
  18.219 +			sound2Skip = SOUND_MAGIC / freq;
  18.220 +		}
  18.221 +		else
  18.222 +			sound2Skip = 0;
  18.223 +		if (data & 0x80)
  18.224 +		{
  18.225 +			gbMemory[NR52]		|= 2;
  18.226 +			sound2EnvelopeVolume = gbMemory[NR22] >> 4;
  18.227 +			sound2EnvelopeUpDown = gbMemory[NR22] & 0x08;
  18.228 +			sound2ATL = 172 * (64 - (gbMemory[NR21] & 0x3f));
  18.229 +			sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (gbMemory[NR22] & 7);
  18.230 +
  18.231 +			sound2Index = 0;
  18.232 +			sound2On	= 1;
  18.233 +		}
  18.234 +		break;
  18.235 +	case NR30:
  18.236 +		if (!(data & 0x80))
  18.237 +		{
  18.238 +			gbMemory[NR52] &= 0xfb;
  18.239 +			sound3On		= 0;
  18.240 +		}
  18.241 +		break;
  18.242 +	case NR31:
  18.243 +		sound3ATL = 172 * (256 - data);
  18.244 +		break;
  18.245 +	case NR32:
  18.246 +		sound3OutputLevel = (data >> 5) & 3;
  18.247 +		break;
  18.248 +	case NR33:
  18.249 +		freq = 2048 - (((int)(gbMemory[NR34] & 7) << 8) | data);
  18.250 +		if (freq)
  18.251 +		{
  18.252 +			sound3Skip = SOUND_MAGIC_2 / freq;
  18.253 +		}
  18.254 +		else
  18.255 +			sound3Skip = 0;
  18.256 +		break;
  18.257 +	case NR34:
  18.258 +		freq = 2048 - (((data & 7) << 8) | (int)gbMemory[NR33]);
  18.259 +		if (freq)
  18.260 +		{
  18.261 +			sound3Skip = SOUND_MAGIC_2 / freq;
  18.262 +		}
  18.263 +		else
  18.264 +		{
  18.265 +			sound3Skip = 0;
  18.266 +		}
  18.267 +		sound3Continue = data & 0x40;
  18.268 +		if ((data & 0x80) && (gbMemory[NR30] & 0x80))
  18.269 +		{
  18.270 +			gbMemory[NR52] |= 4;
  18.271 +			sound3ATL		= 172 * (256 - gbMemory[NR31]);
  18.272 +			sound3Index		= 0;
  18.273 +			sound3On		= 1;
  18.274 +		}
  18.275 +		break;
  18.276 +	case NR41:
  18.277 +		sound4ATL = 172 * (64 - (data & 0x3f));
  18.278 +		break;
  18.279 +	case NR42:
  18.280 +		sound4EnvelopeVolume	= data >> 4;
  18.281 +		sound4EnvelopeUpDown	= data & 0x08;
  18.282 +		sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (data & 7);
  18.283 +		break;
  18.284 +	case NR43:
  18.285 +		freq		 = soundFreqRatio[data & 7];
  18.286 +		sound4NSteps = data & 0x08;
  18.287 +
  18.288 +		sound4Skip = freq * NOISE_MAGIC;
  18.289 +
  18.290 +		sound4Clock = data >> 4;
  18.291 +
  18.292 +		freq = freq / soundShiftClock[sound4Clock];
  18.293 +
  18.294 +		sound4ShiftSkip = freq * NOISE_MAGIC;
  18.295 +
  18.296 +		break;
  18.297 +	case NR44:
  18.298 +		sound4Continue = data & 0x40;
  18.299 +		if (data & 0x80)
  18.300 +		{
  18.301 +			gbMemory[NR52]		|= 8;
  18.302 +			sound4EnvelopeVolume = gbMemory[NR42] >> 4;
  18.303 +			sound4EnvelopeUpDown = gbMemory[NR42] & 0x08;
  18.304 +			sound4ATL = 172 * (64 - (gbMemory[NR41] & 0x3f));
  18.305 +			sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (gbMemory[NR42] & 7);
  18.306 +
  18.307 +			sound4On = 1;
  18.308 +
  18.309 +			sound4Index		 = 0;
  18.310 +			sound4ShiftIndex = 0;
  18.311 +
  18.312 +			freq = soundFreqRatio[gbMemory[NR43] & 7];
  18.313 +
  18.314 +			sound4Skip = freq * NOISE_MAGIC;
  18.315 +
  18.316 +			sound4NSteps = gbMemory[NR43] & 0x08;
  18.317 +
  18.318 +			freq = freq / soundShiftClock[gbMemory[NR43] >> 4];
  18.319 +
  18.320 +			sound4ShiftSkip = freq * NOISE_MAGIC;
  18.321 +			if (sound4NSteps)
  18.322 +				sound4ShiftRight = 0x7f;
  18.323 +			else
  18.324 +				sound4ShiftRight = 0x7fff;
  18.325 +		}
  18.326 +		break;
  18.327 +	case NR50:
  18.328 +		soundVIN	= data & 0x88;
  18.329 +		soundLevel1 = data & 7;
  18.330 +		soundLevel2 = (data >> 4) & 7;
  18.331 +		break;
  18.332 +	case NR51:
  18.333 +		soundBalance	  = (data & soundEnableFlag);
  18.334 +		gbMemory[address] = data;
  18.335 +		break;
  18.336 +	case NR52:
  18.337 +		soundMasterOn = data & 0x80;
  18.338 +		if (!(data & 0x80))
  18.339 +		{
  18.340 +			sound1On = 0;
  18.341 +			sound2On = 0;
  18.342 +			sound3On = 0;
  18.343 +			sound4On = 0;
  18.344 +		}
  18.345 +		break;
  18.346 +	}
  18.347 +
  18.348 +	gbDigitalSound = true;
  18.349 +
  18.350 +	if (sound1On && sound1EnvelopeVolume != 0)
  18.351 +		gbDigitalSound = false;
  18.352 +	if (sound2On && sound2EnvelopeVolume != 0)
  18.353 +		gbDigitalSound = false;
  18.354 +	if (sound3On && sound3OutputLevel != 0)
  18.355 +		gbDigitalSound = false;
  18.356 +	if (sound4On && sound4EnvelopeVolume != 0)
  18.357 +		gbDigitalSound = false;
  18.358 +}
  18.359 +
  18.360 +void gbSoundChannel1()
  18.361 +{
  18.362 +	int vol = sound1EnvelopeVolume;
  18.363 +
  18.364 +	int freq = 0;
  18.365 +
  18.366 +	int value = 0;
  18.367 +
  18.368 +	if (sound1On && (sound1ATL || !sound1Continue))
  18.369 +	{
  18.370 +		sound1Index += soundQuality * sound1Skip;
  18.371 +		sound1Index &= 0x1fffffff;
  18.372 +
  18.373 +		value = ((s8)sound1Wave[sound1Index >> 24]) * vol;
  18.374 +	}
  18.375 +
  18.376 +	soundBuffer[0][soundIndex] = value;
  18.377 +
  18.378 +	if (sound1On)
  18.379 +	{
  18.380 +		if (sound1ATL)
  18.381 +		{
  18.382 +			sound1ATL -= soundQuality;
  18.383 +
  18.384 +			if (sound1ATL <= 0 && sound1Continue)
  18.385 +			{
  18.386 +				gbMemory[NR52] &= 0xfe;
  18.387 +				sound1On		= 0;
  18.388 +			}
  18.389 +		}
  18.390 +
  18.391 +		if (sound1EnvelopeATL)
  18.392 +		{
  18.393 +			sound1EnvelopeATL -= soundQuality;
  18.394 +
  18.395 +			if (sound1EnvelopeATL <= 0)
  18.396 +			{
  18.397 +				if (sound1EnvelopeUpDown)
  18.398 +				{
  18.399 +					if (sound1EnvelopeVolume < 15)
  18.400 +						sound1EnvelopeVolume++;
  18.401 +				}
  18.402 +				else
  18.403 +				{
  18.404 +					if (sound1EnvelopeVolume)
  18.405 +						sound1EnvelopeVolume--;
  18.406 +				}
  18.407 +
  18.408 +				sound1EnvelopeATL += sound1EnvelopeATLReload;
  18.409 +			}
  18.410 +		}
  18.411 +
  18.412 +		if (sound1SweepATL)
  18.413 +		{
  18.414 +			sound1SweepATL -= soundQuality;
  18.415 +
  18.416 +			if (sound1SweepATL <= 0)
  18.417 +			{
  18.418 +				freq = (((int)(gbMemory[NR14] & 7) << 8) | gbMemory[NR13]);
  18.419 +
  18.420 +				int updown = 1;
  18.421 +
  18.422 +				if (sound1SweepUpDown)
  18.423 +					updown = -1;
  18.424 +
  18.425 +				int newfreq = 0;
  18.426 +				if (sound1SweepSteps)
  18.427 +				{
  18.428 +					newfreq = freq + updown * freq / (1 << sound1SweepSteps);
  18.429 +					if (newfreq == freq)
  18.430 +						newfreq = 0;
  18.431 +				}
  18.432 +				else
  18.433 +					newfreq = freq;
  18.434 +
  18.435 +				if (newfreq < 0)
  18.436 +				{
  18.437 +					sound1SweepATL += sound1SweepATLReload;
  18.438 +				}
  18.439 +				else if (newfreq > 2047)
  18.440 +				{
  18.441 +					sound1SweepATL	= 0;
  18.442 +					sound1On		= 0;
  18.443 +					gbMemory[NR52] &= 0xfe;
  18.444 +				}
  18.445 +				else
  18.446 +				{
  18.447 +					sound1SweepATL += sound1SweepATLReload;
  18.448 +					sound1Skip		= SOUND_MAGIC / (2048 - newfreq);
  18.449 +
  18.450 +					gbMemory[NR13] = newfreq & 0xff;
  18.451 +					gbMemory[NR14] = (gbMemory[NR14] & 0xf8) | ((newfreq >> 8) & 7);
  18.452 +				}
  18.453 +			}
  18.454 +		}
  18.455 +	}
  18.456 +}
  18.457 +
  18.458 +void gbSoundChannel2()
  18.459 +{
  18.460 +	//  int freq = 0;
  18.461 +	int vol = sound2EnvelopeVolume;
  18.462 +
  18.463 +	int value = 0;
  18.464 +
  18.465 +	if (sound2On && (sound2ATL || !sound2Continue))
  18.466 +	{
  18.467 +		sound2Index += soundQuality * sound2Skip;
  18.468 +		sound2Index &= 0x1fffffff;
  18.469 +
  18.470 +		value = ((s8)sound2Wave[sound2Index >> 24]) * vol;
  18.471 +	}
  18.472 +
  18.473 +	soundBuffer[1][soundIndex] = value;
  18.474 +
  18.475 +	if (sound2On)
  18.476 +	{
  18.477 +		if (sound2ATL)
  18.478 +		{
  18.479 +			sound2ATL -= soundQuality;
  18.480 +
  18.481 +			if (sound2ATL <= 0 && sound2Continue)
  18.482 +			{
  18.483 +				gbMemory[NR52] &= 0xfd;
  18.484 +				sound2On		= 0;
  18.485 +			}
  18.486 +		}
  18.487 +
  18.488 +		if (sound2EnvelopeATL)
  18.489 +		{
  18.490 +			sound2EnvelopeATL -= soundQuality;
  18.491 +
  18.492 +			if (sound2EnvelopeATL <= 0)
  18.493 +			{
  18.494 +				if (sound2EnvelopeUpDown)
  18.495 +				{
  18.496 +					if (sound2EnvelopeVolume < 15)
  18.497 +						sound2EnvelopeVolume++;
  18.498 +				}
  18.499 +				else
  18.500 +				{
  18.501 +					if (sound2EnvelopeVolume)
  18.502 +						sound2EnvelopeVolume--;
  18.503 +				}
  18.504 +				sound2EnvelopeATL += sound2EnvelopeATLReload;
  18.505 +			}
  18.506 +		}
  18.507 +	}
  18.508 +}
  18.509 +
  18.510 +void gbSoundChannel3()
  18.511 +{
  18.512 +	int value = sound3Last;
  18.513 +
  18.514 +	if (sound3On && (sound3ATL || !sound3Continue))
  18.515 +	{
  18.516 +		sound3Index += soundQuality * sound3Skip;
  18.517 +		sound3Index &= 0x1fffffff;
  18.518 +
  18.519 +		value = gbMemory[0xff30 + (sound3Index >> 25)];
  18.520 +
  18.521 +		if ((sound3Index & 0x01000000))
  18.522 +		{
  18.523 +			value &= 0x0f;
  18.524 +		}
  18.525 +		else
  18.526 +		{
  18.527 +			value >>= 4;
  18.528 +		}
  18.529 +
  18.530 +		value -= 8;
  18.531 +		value *= 2;
  18.532 +
  18.533 +		switch (sound3OutputLevel)
  18.534 +		{
  18.535 +		case 0:
  18.536 +			value = 0;
  18.537 +			break;
  18.538 +		case 1:
  18.539 +			break;
  18.540 +		case 2:
  18.541 +			value = (value >> 1);
  18.542 +			break;
  18.543 +		case 3:
  18.544 +			value = (value >> 2);
  18.545 +			break;
  18.546 +		}
  18.547 +		//value += 1;
  18.548 +		sound3Last = value;
  18.549 +	}
  18.550 +
  18.551 +	soundBuffer[2][soundIndex] = value;
  18.552 +
  18.553 +	if (sound3On)
  18.554 +	{
  18.555 +		if (sound3ATL)
  18.556 +		{
  18.557 +			sound3ATL -= soundQuality;
  18.558 +
  18.559 +			if (sound3ATL <= 0 && sound3Continue)
  18.560 +			{
  18.561 +				gbMemory[NR52] &= 0xfb;
  18.562 +				sound3On		= 0;
  18.563 +			}
  18.564 +		}
  18.565 +	}
  18.566 +}
  18.567 +
  18.568 +void gbSoundChannel4()
  18.569 +{
  18.570 +	int vol = sound4EnvelopeVolume;
  18.571 +
  18.572 +	int value = 0;
  18.573 +
  18.574 +	if (sound4Clock <= 0x0c)
  18.575 +	{
  18.576 +		if (sound4On && (sound4ATL || !sound4Continue))
  18.577 +		{
  18.578 +	  #define NOISE_ONE_SAMP_SCALE  0x200000
  18.579 +
  18.580 +			sound4Index		 += soundQuality * sound4Skip;
  18.581 +			sound4ShiftIndex += soundQuality * sound4ShiftSkip;
  18.582 +
  18.583 +			if (sound4NSteps)
  18.584 +			{
  18.585 +				while (sound4ShiftIndex >= NOISE_ONE_SAMP_SCALE)
  18.586 +				{
  18.587 +					sound4ShiftRight = (((sound4ShiftRight << 6) ^
  18.588 +					                     (sound4ShiftRight << 5)) & 0x40) |
  18.589 +					                   (sound4ShiftRight >> 1);
  18.590 +					sound4ShiftIndex -= NOISE_ONE_SAMP_SCALE;
  18.591 +				}
  18.592 +			}
  18.593 +			else
  18.594 +			{
  18.595 +				while (sound4ShiftIndex >= NOISE_ONE_SAMP_SCALE)
  18.596 +				{
  18.597 +					sound4ShiftRight = (((sound4ShiftRight << 14) ^
  18.598 +					                     (sound4ShiftRight << 13)) & 0x4000) |
  18.599 +					                   (sound4ShiftRight >> 1);
  18.600 +
  18.601 +					sound4ShiftIndex -= NOISE_ONE_SAMP_SCALE;
  18.602 +				}
  18.603 +			}
  18.604 +
  18.605 +			sound4Index		 %= NOISE_ONE_SAMP_SCALE;
  18.606 +			sound4ShiftIndex %= NOISE_ONE_SAMP_SCALE;
  18.607 +
  18.608 +			value = ((sound4ShiftRight & 1) * 2 - 1) * vol;
  18.609 +		}
  18.610 +		else
  18.611 +		{
  18.612 +			value = 0;
  18.613 +		}
  18.614 +	}
  18.615 +
  18.616 +	soundBuffer[3][soundIndex] = value;
  18.617 +
  18.618 +	if (sound4On)
  18.619 +	{
  18.620 +		if (sound4ATL)
  18.621 +		{
  18.622 +			sound4ATL -= soundQuality;
  18.623 +
  18.624 +			if (sound4ATL <= 0 && sound4Continue)
  18.625 +			{
  18.626 +				gbMemory[NR52] &= 0xfd;
  18.627 +				sound4On		= 0;
  18.628 +			}
  18.629 +		}
  18.630 +
  18.631 +		if (sound4EnvelopeATL)
  18.632 +		{
  18.633 +			sound4EnvelopeATL -= soundQuality;
  18.634 +
  18.635 +			if (sound4EnvelopeATL <= 0)
  18.636 +			{
  18.637 +				if (sound4EnvelopeUpDown)
  18.638 +				{
  18.639 +					if (sound4EnvelopeVolume < 15)
  18.640 +						sound4EnvelopeVolume++;
  18.641 +				}
  18.642 +				else
  18.643 +				{
  18.644 +					if (sound4EnvelopeVolume)
  18.645 +						sound4EnvelopeVolume--;
  18.646 +				}
  18.647 +				sound4EnvelopeATL += sound4EnvelopeATLReload;
  18.648 +			}
  18.649 +		}
  18.650 +	}
  18.651 +}
  18.652 +
  18.653 +void gbSoundMix()
  18.654 +{
  18.655 +	int res = 0;
  18.656 +
  18.657 +	if (gbMemory)
  18.658 +		soundBalance = (gbMemory[NR51] & soundEnableFlag & ~soundMutedFlag);
  18.659 +
  18.660 +	if (soundBalance & 16)
  18.661 +	{
  18.662 +		res += ((s8)soundBuffer[0][soundIndex]);
  18.663 +	}
  18.664 +	if (soundBalance & 32)
  18.665 +	{
  18.666 +		res += ((s8)soundBuffer[1][soundIndex]);
  18.667 +	}
  18.668 +	if (soundBalance & 64)
  18.669 +	{
  18.670 +		res += ((s8)soundBuffer[2][soundIndex]);
  18.671 +	}
  18.672 +	if (soundBalance & 128)
  18.673 +	{
  18.674 +		res += ((s8)soundBuffer[3][soundIndex]);
  18.675 +	}
  18.676 +
  18.677 +	if (gbDigitalSound)
  18.678 +		res = soundLevel1 * 256;
  18.679 +	else
  18.680 +		res *= soundLevel1 * 60;
  18.681 +
  18.682 +	if (soundEcho)
  18.683 +	{
  18.684 +		res *= 2;
  18.685 +		res += soundFilter[soundEchoIndex];
  18.686 +		res /= 2;
  18.687 +		soundFilter[soundEchoIndex++] = res;
  18.688 +	}
  18.689 +
  18.690 +	if (soundLowPass)
  18.691 +	{
  18.692 +		soundLeft[4] = soundLeft[3];
  18.693 +		soundLeft[3] = soundLeft[2];
  18.694 +		soundLeft[2] = soundLeft[1];
  18.695 +		soundLeft[1] = soundLeft[0];
  18.696 +		soundLeft[0] = res;
  18.697 +		res = (soundLeft[4] + 2 * soundLeft[3] + 8 * soundLeft[2] + 2 * soundLeft[1] +
  18.698 +		       soundLeft[0]) / 14;
  18.699 +	}
  18.700 +
  18.701 +	bool noSpecialEffects = false;
  18.702 +#if (defined(WIN32) && !defined(SDL))
  18.703 +	if (theApp.soundRecording || theApp.aviRecording || theApp.nvAudioLog)
  18.704 +		noSpecialEffects = true;
  18.705 +#endif
  18.706 +
  18.707 +	if (!noSpecialEffects)
  18.708 +	{
  18.709 +		switch (soundVolume)
  18.710 +		{
  18.711 +		case 0:
  18.712 +		case 1:
  18.713 +		case 2:
  18.714 +		case 3:
  18.715 +			res *= (soundVolume + 1);
  18.716 +			break;
  18.717 +		case 4:
  18.718 +			res >>= 2;
  18.719 +			break;
  18.720 +		case 5:
  18.721 +			res >>= 1;
  18.722 +			break;
  18.723 +		}
  18.724 +	}
  18.725 +
  18.726 +	if (res > 32767)
  18.727 +		res = 32767;
  18.728 +	if (res < -32768)
  18.729 +		res = -32768;
  18.730 +
  18.731 +	if (soundReverse && !noSpecialEffects)
  18.732 +	{
  18.733 +		soundFinalWave[++soundBufferIndex] = res;
  18.734 +		if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound))
  18.735 +			/*assert(false)*/;
  18.736 +		else
  18.737 +			soundFrameSound[++soundFrameSoundWritten] = res;
  18.738 +	}
  18.739 +	else
  18.740 +	{
  18.741 +		soundFinalWave[soundBufferIndex++] = res;
  18.742 +		if (soundFrameSoundWritten >= countof(soundFrameSound))
  18.743 +			/*assert(false)*/;
  18.744 +		else
  18.745 +			soundFrameSound[soundFrameSoundWritten++] = res;
  18.746 +	}
  18.747 +
  18.748 +	res = 0;
  18.749 +
  18.750 +	if (soundBalance & 1)
  18.751 +	{
  18.752 +		res += ((s8)soundBuffer[0][soundIndex]);
  18.753 +	}
  18.754 +	if (soundBalance & 2)
  18.755 +	{
  18.756 +		res += ((s8)soundBuffer[1][soundIndex]);
  18.757 +	}
  18.758 +	if (soundBalance & 4)
  18.759 +	{
  18.760 +		res += ((s8)soundBuffer[2][soundIndex]);
  18.761 +	}
  18.762 +	if (soundBalance & 8)
  18.763 +	{
  18.764 +		res += ((s8)soundBuffer[3][soundIndex]);
  18.765 +	}
  18.766 +
  18.767 +	if (gbDigitalSound)
  18.768 +		res = soundLevel2 * 256;
  18.769 +	else
  18.770 +		res *= soundLevel2 * 60;
  18.771 +
  18.772 +	if (soundEcho)
  18.773 +	{
  18.774 +		res *= 2;
  18.775 +		res += soundFilter[soundEchoIndex];
  18.776 +		res /= 2;
  18.777 +		soundFilter[soundEchoIndex++] = res;
  18.778 +
  18.779 +		if (soundEchoIndex >= 4000)
  18.780 +			soundEchoIndex = 0;
  18.781 +	}
  18.782 +
  18.783 +	if (soundLowPass)
  18.784 +	{
  18.785 +		soundRight[4] = soundRight[3];
  18.786 +		soundRight[3] = soundRight[2];
  18.787 +		soundRight[2] = soundRight[1];
  18.788 +		soundRight[1] = soundRight[0];
  18.789 +		soundRight[0] = res;
  18.790 +		res = (soundRight[4] + 2 * soundRight[3] + 8 * soundRight[2] + 2 * soundRight[1] +
  18.791 +		       soundRight[0]) / 14;
  18.792 +	}
  18.793 +
  18.794 +	if (!noSpecialEffects)
  18.795 +	{
  18.796 +		switch (soundVolume)
  18.797 +		{
  18.798 +		case 0:
  18.799 +		case 1:
  18.800 +		case 2:
  18.801 +		case 3:
  18.802 +			res *= (soundVolume + 1);
  18.803 +			break;
  18.804 +		case 4:
  18.805 +			res >>= 2;
  18.806 +			break;
  18.807 +		case 5:
  18.808 +			res >>= 1;
  18.809 +			break;
  18.810 +		}
  18.811 +	}
  18.812 +
  18.813 +	if (res > 32767)
  18.814 +		res = 32767;
  18.815 +	if (res < -32768)
  18.816 +		res = -32768;
  18.817 +
  18.818 +	if (soundReverse && !noSpecialEffects)
  18.819 +	{
  18.820 +		soundFinalWave[-1 + soundBufferIndex++]		   = res;
  18.821 +		if ((soundFrameSoundWritten) >= countof(soundFrameSound))
  18.822 +			/*assert(false)*/;
  18.823 +		else
  18.824 +			soundFrameSound[-1 + soundFrameSoundWritten++] = res;
  18.825 +	}
  18.826 +	else
  18.827 +	{
  18.828 +		soundFinalWave[soundBufferIndex++]			  = res;
  18.829 +		if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound))
  18.830 +			/*assert(false)*/;
  18.831 +		else
  18.832 +			soundFrameSound[soundFrameSoundWritten++] = res;
  18.833 +	}
  18.834 +}
  18.835 +
  18.836 +void gbSoundTick()
  18.837 +{
  18.838 +	if (systemSoundOn)
  18.839 +	{
  18.840 +		if (soundMasterOn)
  18.841 +		{
  18.842 +			gbSoundChannel1();
  18.843 +			gbSoundChannel2();
  18.844 +			gbSoundChannel3();
  18.845 +			gbSoundChannel4();
  18.846 +
  18.847 +			gbSoundMix();
  18.848 +		}
  18.849 +		else
  18.850 +		{
  18.851 +			soundFinalWave[soundBufferIndex++] = 0;
  18.852 +			soundFinalWave[soundBufferIndex++] = 0;
  18.853 +			if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound))
  18.854 +				/*assert(false)*/;
  18.855 +			else
  18.856 +			{
  18.857 +				soundFrameSound[soundFrameSoundWritten++] = 0;
  18.858 +				soundFrameSound[soundFrameSoundWritten++] = 0;
  18.859 +			}
  18.860 +		}
  18.861 +
  18.862 +		soundIndex++;
  18.863 +
  18.864 +		if (2 * soundBufferIndex >= soundBufferLen)
  18.865 +		{
  18.866 +			if (systemSoundOn)
  18.867 +			{
  18.868 +				if (soundPaused)
  18.869 +				{
  18.870 +					extern void soundResume();
  18.871 +					soundResume();
  18.872 +				}
  18.873 +
  18.874 +				systemSoundWriteToBuffer();
  18.875 +			}
  18.876 +			soundIndex		 = 0;
  18.877 +			soundBufferIndex = 0;
  18.878 +		}
  18.879 +	}
  18.880 +}
  18.881 +
  18.882 +void gbSoundReset()
  18.883 +{
  18.884 +	soundPaused		  = 1;
  18.885 +	soundPlay		  = 0;
  18.886 +	SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS;
  18.887 +//  soundTicks = SOUND_CLOCK_TICKS;
  18.888 +	soundTicks		  = 0;
  18.889 +	soundNextPosition = 0;
  18.890 +	soundMasterOn	  = 1;
  18.891 +	soundIndex		  = 0;
  18.892 +	soundBufferIndex  = 0;
  18.893 +	soundLevel1		  = 7;
  18.894 +	soundLevel2		  = 7;
  18.895 +	soundVIN = 0;
  18.896 +
  18.897 +	sound1On = 0;
  18.898 +	sound1ATL = 0;
  18.899 +	sound1Skip = 0;
  18.900 +	sound1Index = 0;
  18.901 +	sound1Continue = 0;
  18.902 +	sound1EnvelopeVolume	= 0;
  18.903 +	sound1EnvelopeATL		= 0;
  18.904 +	sound1EnvelopeUpDown	= 0;
  18.905 +	sound1EnvelopeATLReload = 0;
  18.906 +	sound1SweepATL			= 0;
  18.907 +	sound1SweepATLReload	= 0;
  18.908 +	sound1SweepSteps		= 0;
  18.909 +	sound1SweepUpDown		= 0;
  18.910 +	sound1SweepStep			= 0;
  18.911 +	sound1Wave				= soundWavePattern[2];
  18.912 +
  18.913 +	sound2On = 0;
  18.914 +	sound2ATL = 0;
  18.915 +	sound2Skip = 0;
  18.916 +	sound2Index = 0;
  18.917 +	sound2Continue = 0;
  18.918 +	sound2EnvelopeVolume	= 0;
  18.919 +	sound2EnvelopeATL		= 0;
  18.920 +	sound2EnvelopeUpDown	= 0;
  18.921 +	sound2EnvelopeATLReload = 0;
  18.922 +	sound2Wave				= soundWavePattern[2];
  18.923 +
  18.924 +	sound3On = 0;
  18.925 +	sound3ATL		  = 0;
  18.926 +	sound3Skip		  = 0;
  18.927 +	sound3Index		  = 0;
  18.928 +	sound3Continue	  = 0;
  18.929 +	sound3OutputLevel = 0;
  18.930 +
  18.931 +	sound4On = 0;
  18.932 +	sound4Clock = 0;
  18.933 +	sound4ATL = 0;
  18.934 +	sound4Skip = 0;
  18.935 +	sound4Index = 0;
  18.936 +	sound4ShiftRight		= 0x7f;
  18.937 +	sound4NSteps			= 0;
  18.938 +	sound4CountDown			= 0;
  18.939 +	sound4Continue			= 0;
  18.940 +	sound4EnvelopeVolume	= 0;
  18.941 +	sound4EnvelopeATL		= 0;
  18.942 +	sound4EnvelopeUpDown	= 0;
  18.943 +	sound4EnvelopeATLReload = 0;
  18.944 +
  18.945 +	// don't translate
  18.946 +	if (soundDebug)
  18.947 +	{
  18.948 +		log("*** Sound Init ***\n");
  18.949 +	}
  18.950 +
  18.951 +	gbSoundEvent(0xff10, 0x80);
  18.952 +	gbSoundEvent(0xff11, 0xbf);
  18.953 +	gbSoundEvent(0xff12, 0xf3);
  18.954 +	gbSoundEvent(0xff14, 0xbf);
  18.955 +	gbSoundEvent(0xff16, 0x3f);
  18.956 +	gbSoundEvent(0xff17, 0x00);
  18.957 +	gbSoundEvent(0xff19, 0xbf);
  18.958 +
  18.959 +	gbSoundEvent(0xff1a, 0x7f);
  18.960 +	gbSoundEvent(0xff1b, 0xff);
  18.961 +	gbSoundEvent(0xff1c, 0xbf);
  18.962 +	gbSoundEvent(0xff1e, 0xbf);
  18.963 +
  18.964 +	gbSoundEvent(0xff20, 0xff);
  18.965 +	gbSoundEvent(0xff21, 0x00);
  18.966 +	gbSoundEvent(0xff22, 0x00);
  18.967 +	gbSoundEvent(0xff23, 0xbf);
  18.968 +	gbSoundEvent(0xff24, 0x77);
  18.969 +	gbSoundEvent(0xff25, 0xf3);
  18.970 +
  18.971 +	gbSoundEvent(0xff26, 0xf0);
  18.972 +
  18.973 +	// don't translate
  18.974 +	if (soundDebug)
  18.975 +	{
  18.976 +		log("*** Sound Init Complete ***\n");
  18.977 +	}
  18.978 +
  18.979 +	sound1On = 0;
  18.980 +	sound2On = 0;
  18.981 +	sound3On = 0;
  18.982 +	sound4On = 0;
  18.983 +
  18.984 +	int addr = 0xff30;
  18.985 +
  18.986 +	while (addr < 0xff40)
  18.987 +	{
  18.988 +		gbMemory[addr++] = 0x00;
  18.989 +		gbMemory[addr++] = 0xff;
  18.990 +	}
  18.991 +
  18.992 +	memset(soundFinalWave, 0x00, soundBufferLen);
  18.993 +
  18.994 +	memset(soundFilter, 0, sizeof(soundFilter));
  18.995 +	soundEchoIndex = 0;
  18.996 +}
  18.997 +
  18.998 +extern bool soundInit();
  18.999 +extern void soundShutdown();
 18.1000 +
 18.1001 +void gbSoundSetQuality(int quality)
 18.1002 +{
 18.1003 +	if (soundQuality != quality && systemSoundCanChangeQuality())
 18.1004 +	{
 18.1005 +		if (!soundOffFlag)
 18.1006 +			soundShutdown();
 18.1007 +		soundQuality	  = quality;
 18.1008 +		soundNextPosition = 0;
 18.1009 +		if (!soundOffFlag)
 18.1010 +			soundInit();
 18.1011 +		SOUND_CLOCK_TICKS = (gbSpeed ? 2 : 1) * GB_USE_TICKS_AS * soundQuality;
 18.1012 +		soundIndex		  = 0;
 18.1013 +		soundBufferIndex  = 0;
 18.1014 +	}
 18.1015 +	else
 18.1016 +	{
 18.1017 +		soundNextPosition = 0;
 18.1018 +		SOUND_CLOCK_TICKS = (gbSpeed ? 2 : 1) * GB_USE_TICKS_AS * soundQuality;
 18.1019 +		soundIndex		  = 0;
 18.1020 +		soundBufferIndex  = 0;
 18.1021 +	}
 18.1022 +}
 18.1023 +
 18.1024 +static int32 soundTicks_int32;
 18.1025 +static int32 SOUND_CLOCK_TICKS_int32;
 18.1026 +variable_desc gbSoundSaveStruct[] = {
 18.1027 +	{ &soundPaused,				sizeof(int32)					  },
 18.1028 +	{ &soundPlay,				sizeof(int32)					  },
 18.1029 +	{ &soundTicks_int32,		sizeof(int32)					  },
 18.1030 +	{ &SOUND_CLOCK_TICKS_int32, sizeof(int32)					  },
 18.1031 +	{ &soundLevel1,				sizeof(int32)					  },
 18.1032 +	{ &soundLevel2,				sizeof(int32)					  },
 18.1033 +	{ &soundBalance,			sizeof(int32)					  },
 18.1034 +	{ &soundMasterOn,			sizeof(int32)					  },
 18.1035 +	{ &soundIndex,				sizeof(int32)					  },
 18.1036 +	{ &soundVIN,				sizeof(int32)					  },
 18.1037 +	{ &sound1On,				sizeof(int32)					  },
 18.1038 +	{ &sound1ATL,				sizeof(int32)					  },
 18.1039 +	{ &sound1Skip,				sizeof(int32)					  },
 18.1040 +	{ &sound1Index,				sizeof(int32)					  },
 18.1041 +	{ &sound1Continue,			sizeof(int32)					  },
 18.1042 +	{ &sound1EnvelopeVolume,	sizeof(int32)					  },
 18.1043 +	{ &sound1EnvelopeATL,		sizeof(int32)					  },
 18.1044 +	{ &sound1EnvelopeATLReload, sizeof(int32)					  },
 18.1045 +	{ &sound1EnvelopeUpDown,	sizeof(int32)					  },
 18.1046 +	{ &sound1SweepATL,			sizeof(int32)					  },
 18.1047 +	{ &sound1SweepATLReload,	sizeof(int32)					  },
 18.1048 +	{ &sound1SweepSteps,		sizeof(int32)					  },
 18.1049 +	{ &sound1SweepUpDown,		sizeof(int32)					  },
 18.1050 +	{ &sound1SweepStep,			sizeof(int32)					  },
 18.1051 +	{ &sound2On,				sizeof(int32)					  },
 18.1052 +	{ &sound2ATL,				sizeof(int32)					  },
 18.1053 +	{ &sound2Skip,				sizeof(int32)					  },
 18.1054 +	{ &sound2Index,				sizeof(int32)					  },
 18.1055 +	{ &sound2Continue,			sizeof(int32)					  },
 18.1056 +	{ &sound2EnvelopeVolume,	sizeof(int32)					  },
 18.1057 +	{ &sound2EnvelopeATL,		sizeof(int32)					  },
 18.1058 +	{ &sound2EnvelopeATLReload, sizeof(int32)					  },
 18.1059 +	{ &sound2EnvelopeUpDown,	sizeof(int32)					  },
 18.1060 +	{ &sound3On,				sizeof(int32)					  },
 18.1061 +	{ &sound3ATL,				sizeof(int32)					  },
 18.1062 +	{ &sound3Skip,				sizeof(int32)					  },
 18.1063 +	{ &sound3Index,				sizeof(int32)					  },
 18.1064 +	{ &sound3Continue,			sizeof(int32)					  },
 18.1065 +	{ &sound3OutputLevel,		sizeof(int32)					  },
 18.1066 +	{ &sound4On,				sizeof(int32)					  },
 18.1067 +	{ &sound4ATL,				sizeof(int32)					  },
 18.1068 +	{ &sound4Skip,				sizeof(int32)					  },
 18.1069 +	{ &sound4Index,				sizeof(int32)					  },
 18.1070 +	{ &sound4Clock,				sizeof(int32)					  },
 18.1071 +	{ &sound4ShiftRight,		sizeof(int32)					  },
 18.1072 +	{ &sound4ShiftSkip,			sizeof(int32)					  },
 18.1073 +	{ &sound4ShiftIndex,		sizeof(int32)					  },
 18.1074 +	{ &sound4NSteps,			sizeof(int32)					  },
 18.1075 +	{ &sound4CountDown,			sizeof(int32)					  },
 18.1076 +	{ &sound4Continue,			sizeof(int32)					  },
 18.1077 +	{ &sound4EnvelopeVolume,	sizeof(int32)					  },
 18.1078 +	{ &sound4EnvelopeATL,		sizeof(int32)					  },
 18.1079 +	{ &sound4EnvelopeATLReload, sizeof(int32)					  },
 18.1080 +	{ &sound4EnvelopeUpDown,	sizeof(int32)					  },
 18.1081 +	{ &soundEnableFlag,			sizeof(int32)					  },
 18.1082 +	{ NULL,						0								  }
 18.1083 +};
 18.1084 +
 18.1085 +//variable_desc gbSoundSaveStructV2[] = {
 18.1086 +//  { &soundTicks, sizeof(soundtick_t) },
 18.1087 +//  { &SOUND_CLOCK_TICKS, sizeof(soundtick_t) },
 18.1088 +//  { &GB_USE_TICKS_AS, sizeof(soundtick_t) },
 18.1089 +//  { NULL, 0 }
 18.1090 +//};
 18.1091 +
 18.1092 +void gbSoundSaveGame(gzFile gzFile)
 18.1093 +{
 18.1094 +	soundTicks_int32		= (int32) soundTicks;
 18.1095 +	SOUND_CLOCK_TICKS_int32 = (int32) SOUND_CLOCK_TICKS;
 18.1096 +
 18.1097 +	utilWriteData(gzFile, gbSoundSaveStruct);
 18.1098 +
 18.1099 +	utilGzWrite(gzFile, soundBuffer, 4 * 735);
 18.1100 +	utilGzWrite(gzFile, soundFinalWave, 2 * 735);
 18.1101 +	utilGzWrite(gzFile, &soundQuality, sizeof(int32));
 18.1102 +
 18.1103 +	//utilWriteData(gzFile, gbSoundSaveStructV2);
 18.1104 +}
 18.1105 +
 18.1106 +void gbSoundReadGame(int version, gzFile gzFile)
 18.1107 +{
 18.1108 +	int32 oldSoundPaused = soundPaused;
 18.1109 +	int32 oldSoundEnableFlag = soundEnableFlag;
 18.1110 +	utilReadData(gzFile, gbSoundSaveStruct);
 18.1111 +	soundPaused = oldSoundPaused;
 18.1112 +	soundEnableFlag = oldSoundEnableFlag;
 18.1113 +
 18.1114 +	soundBufferIndex = soundIndex * 2;
 18.1115 +
 18.1116 +	utilGzRead(gzFile, soundBuffer, 4 * 735);
 18.1117 +	utilGzRead(gzFile, soundFinalWave, 2 * 735);
 18.1118 +
 18.1119 +	if (version >= 7)
 18.1120 +	{
 18.1121 +		int quality = 1;
 18.1122 +		utilGzRead(gzFile, &quality, sizeof(int32));
 18.1123 +		gbSoundSetQuality(quality);
 18.1124 +	}
 18.1125 +	else
 18.1126 +	{
 18.1127 +		soundQuality = -1;
 18.1128 +		gbSoundSetQuality(1);
 18.1129 +	}
 18.1130 +
 18.1131 +	sound1Wave = soundWavePattern[gbMemory[NR11] >> 6];
 18.1132 +	sound2Wave = soundWavePattern[gbMemory[NR21] >> 6];
 18.1133 +
 18.1134 +	//if(version >= 14) {
 18.1135 +	//  utilReadData(gzFile, gbSoundSaveStructV2);
 18.1136 +	//}
 18.1137 +	//else {
 18.1138 +	soundTicks		  = (soundtick_t) soundTicks_int32;
 18.1139 +	SOUND_CLOCK_TICKS = (soundtick_t) SOUND_CLOCK_TICKS_int32;
 18.1140 +	//}
 18.1141 +}
 18.1142 +
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/gb/gbSound.h	Sat Mar 03 11:44:47 2012 -0600
    19.3 @@ -0,0 +1,51 @@
    19.4 +#ifndef VBA_GB_SOUND_H
    19.5 +#define VBA_GB_SOUND_H
    19.6 +
    19.7 +#if _MSC_VER > 1000
    19.8 +#pragma once
    19.9 +#endif // _MSC_VER > 1000
   19.10 +
   19.11 +#define NR10 0xff10
   19.12 +#define NR11 0xff11
   19.13 +#define NR12 0xff12
   19.14 +#define NR13 0xff13
   19.15 +#define NR14 0xff14
   19.16 +#define NR21 0xff16
   19.17 +#define NR22 0xff17
   19.18 +#define NR23 0xff18
   19.19 +#define NR24 0xff19
   19.20 +#define NR30 0xff1a
   19.21 +#define NR31 0xff1b
   19.22 +#define NR32 0xff1c
   19.23 +#define NR33 0xff1d
   19.24 +#define NR34 0xff1e
   19.25 +#define NR41 0xff20
   19.26 +#define NR42 0xff21
   19.27 +#define NR43 0xff22
   19.28 +#define NR44 0xff23
   19.29 +#define NR50 0xff24
   19.30 +#define NR51 0xff25
   19.31 +#define NR52 0xff26
   19.32 +
   19.33 +#define SOUND_EVENT(address, value) \
   19.34 +    gbSoundEvent(address, value)
   19.35 +
   19.36 +extern void gbSoundTick();
   19.37 +extern void gbSoundPause();
   19.38 +extern void gbSoundResume();
   19.39 +extern void gbSoundEnable(int);
   19.40 +extern void gbSoundDisable(int);
   19.41 +extern int gbSoundGetEnable();
   19.42 +extern void gbSoundReset();
   19.43 +extern void gbSoundSaveGame(gzFile);
   19.44 +extern void gbSoundReadGame(int, gzFile);
   19.45 +extern void gbSoundEvent(register u16, register int);
   19.46 +extern void gbSoundSetQuality(int);
   19.47 +
   19.48 +typedef int32 soundtick_t;
   19.49 +
   19.50 +extern soundtick_t soundTicks;
   19.51 +extern int32       soundQuality;
   19.52 +extern soundtick_t SOUND_CLOCK_TICKS;
   19.53 +
   19.54 +#endif // VBA_GB_SOUND_H