# HG changeset patch # User Robert McIntyre # Date 1330796687 21600 # Node ID 75e5bb1e0aa101e1a08d6139aaa0c28b7723d6dd # Parent 9e598342e182565fc3bf9f4ccf837f08e979544f going to now integrate the gb src tree since it has no dependencies diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/GB.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/GB.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,3918 @@ +#include +#include +#include +#include + +#include "../Port.h" +#include "../NLS.h" +#include "GB.h" +#include "gbCheats.h" +#include "gbGlobals.h" +#include "gbMemory.h" +#include "gbSGB.h" +#include "gbSound.h" +#include "../common/unzip.h" +#include "../common/Util.h" +#include "../common/System.h" +#include "../common/movie.h" +#include "../common/vbalua.h" + +#ifdef __GNUC__ +#define _stricmp strcasecmp +#endif + +// FIXME: constant (GB) or boolean (GBA)?! +#define C_FLAG 0x10 +#define H_FLAG 0x20 +#define N_FLAG 0x40 +#define Z_FLAG 0x80 +extern soundtick_t GB_USE_TICKS_AS; + +u8 * origPix = NULL; +extern u8 * pix; +extern u32 extButtons; +extern bool8 capturePrevious; +extern int32 captureNumber; +extern bool8 speedup; + +bool gbUpdateSizes(); + +// debugging +bool memorydebug = false; +char gbBuffer[2048]; + +extern u16 gbLineMix[160]; + +// mappers +void (*mapper)(u16, u8) = NULL; +void (*mapperRAM)(u16, u8) = NULL; +u8 (*mapperReadRAM)(u16) = NULL; + +// registers +gbRegister PC; +gbRegister SP; +gbRegister AF; +gbRegister BC; +gbRegister DE; +gbRegister HL; +u16 IFF; +// 0xff04 +u8 register_DIV = 0; +// 0xff05 +u8 register_TIMA = 0; +// 0xff06 +u8 register_TMA = 0; +// 0xff07 +u8 register_TAC = 0; +// 0xff0f +u8 register_IF = 0; +// 0xff40 +u8 register_LCDC = 0; +// 0xff41 +u8 register_STAT = 0; +// 0xff42 +u8 register_SCY = 0; +// 0xff43 +u8 register_SCX = 0; +// 0xff44 +u8 register_LY = 0; +// 0xff45 +u8 register_LYC = 0; +// 0xff46 +u8 register_DMA = 0; +// 0xff4a +u8 register_WY = 0; +// 0xff4b +u8 register_WX = 0; +// 0xff4f +u8 register_VBK = 0; +// 0xff51 +u8 register_HDMA1 = 0; +// 0xff52 +u8 register_HDMA2 = 0; +// 0xff53 +u8 register_HDMA3 = 0; +// 0xff54 +u8 register_HDMA4 = 0; +// 0xff55 +u8 register_HDMA5 = 0; +// 0xff70 +u8 register_SVBK = 0; +// 0xffff +u8 register_IE = 0; + +// ticks definition +int32 GBDIV_CLOCK_TICKS = 64; +int32 GBLCD_MODE_0_CLOCK_TICKS = 51; +int32 GBLCD_MODE_1_CLOCK_TICKS = 1140; +int32 GBLCD_MODE_2_CLOCK_TICKS = 20; +int32 GBLCD_MODE_3_CLOCK_TICKS = 43; +int32 GBLY_INCREMENT_CLOCK_TICKS = 114; +int32 GBTIMER_MODE_0_CLOCK_TICKS = 256; +int32 GBTIMER_MODE_1_CLOCK_TICKS = 4; +int32 GBTIMER_MODE_2_CLOCK_TICKS = 16; +int32 GBTIMER_MODE_3_CLOCK_TICKS = 64; +int32 GBSERIAL_CLOCK_TICKS = 128; +int32 GBSYNCHRONIZE_CLOCK_TICKS = 52920; + +// state variables + +// interrupt +int32 gbInterrupt = 0; +int32 gbInterruptWait = 0; +// serial +int32 gbSerialOn = 0; +int32 gbSerialTicks = 0; +int32 gbSerialBits = 0; +// timer +int32 gbTimerOn = 0; +int32 gbTimerTicks = 0; +int32 gbTimerClockTicks = 0; +int32 gbTimerMode = 0; +// lcd +int32 gbLcdMode = 2; +int32 gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS; +int32 gbLcdLYIncrementTicks = 0; +// div +int32 gbDivTicks = GBDIV_CLOCK_TICKS; +// cgb +int32 gbVramBank = 0; +int32 gbWramBank = 1; +int32 gbHdmaSource = 0x0000; +int32 gbHdmaDestination = 0x8000; +int32 gbHdmaBytes = 0x0000; +int32 gbHdmaOn = 0; +int32 gbSpeed = 0; +// frame counting +int32 gbFrameCount = 0; +int32 gbFrameSkip = 0; +int32 gbFrameSkipCount = 0; +// timing +u32 gbLastTime = 0; +u32 gbElapsedTime = 0; +u32 gbTimeNow = 0; +int32 gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS; +int32 gbDMASpeedVersion = 1; +// emulator features +int32 gbBattery = 0; +int32 gbJoymask[4] = { 0, 0, 0, 0 }; + +int32 gbEchoRAMFixOn = 1; + +static bool newFrame = true; +static bool pauseAfterFrameAdvance = false; + +int32 gbRomSizes[] = { 0x00008000, // 32K + 0x00010000, // 64K + 0x00020000, // 128K + 0x00040000, // 256K + 0x00080000, // 512K + 0x00100000, // 1024K + 0x00200000, // 2048K + 0x00400000, // 4096K + 0x00800000 // 8192K +}; +int32 gbRomSizesMasks[] = { 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff }; + +int32 gbRamSizes[6] = { 0x00000000, // 0K + 0x00000800, // 2K + 0x00002000, // 8K + 0x00008000, // 32K + 0x00020000, // 128K + 0x00010000 // 64K +}; + +int32 gbRamSizesMasks[6] = { 0x00000000, + 0x000007ff, + 0x00001fff, + 0x00007fff, + 0x0001ffff, + 0x0000ffff }; + +int32 gbCycles[] = +{ +// 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 + 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1 + 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2 + 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6 + 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b + 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c + 2, 3, 3, 0, 3, 4, 2, 4, 2, 4, 3, 0, 3, 0, 2, 4, // d + 3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4, // e + 3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4 // f +}; + +int32 gbCyclesCB[] = +{ +// 0 1 2 3 4 5 6 7 8 9 a b c d e f + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 8 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 9 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // a + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // b + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // c + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // d + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // e + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 // f +}; + +u16 DAATable[] = +{ + 0x0080, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, + 0x0800, 0x0900, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, + 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, + 0x1800, 0x1900, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, + 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700, + 0x2800, 0x2900, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, + 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, + 0x3800, 0x3900, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, + 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, + 0x4800, 0x4900, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, + 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, + 0x5800, 0x5900, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, + 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, 0x6700, + 0x6800, 0x6900, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, + 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, + 0x7800, 0x7900, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, + 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, + 0x8800, 0x8900, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, + 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700, + 0x9800, 0x9900, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, + 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, + 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, + 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, + 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, + 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, + 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, + 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, + 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, + 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, + 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, + 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, + 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, + 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, 0x6610, 0x6710, + 0x6810, 0x6910, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, + 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, 0x7610, 0x7710, + 0x7810, 0x7910, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, + 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, 0x8610, 0x8710, + 0x8810, 0x8910, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, + 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, 0x9610, 0x9710, + 0x9810, 0x9910, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, + 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, 0xA610, 0xA710, + 0xA810, 0xA910, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, + 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, 0xB610, 0xB710, + 0xB810, 0xB910, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, + 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, 0xC610, 0xC710, + 0xC810, 0xC910, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, + 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, 0xD610, 0xD710, + 0xD810, 0xD910, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, + 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, 0xE610, 0xE710, + 0xE810, 0xE910, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, + 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, 0xF610, 0xF710, + 0xF810, 0xF910, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, + 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, + 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, + 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, + 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, + 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, + 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, + 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, + 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, + 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, + 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, + 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, + 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, + 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, + 0x0E00, 0x0F00, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, + 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, + 0x1E00, 0x1F00, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, + 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00, + 0x2E00, 0x2F00, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, + 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00, + 0x3E00, 0x3F00, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, + 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, + 0x4E00, 0x4F00, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, + 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00, + 0x5E00, 0x5F00, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, + 0x6600, 0x6700, 0x6800, 0x6900, 0x6A00, 0x6B00, 0x6C00, 0x6D00, + 0x6E00, 0x6F00, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, + 0x7600, 0x7700, 0x7800, 0x7900, 0x7A00, 0x7B00, 0x7C00, 0x7D00, + 0x7E00, 0x7F00, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, + 0x8600, 0x8700, 0x8800, 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x8D00, + 0x8E00, 0x8F00, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, + 0x9600, 0x9700, 0x9800, 0x9900, 0x9A00, 0x9B00, 0x9C00, 0x9D00, + 0x9E00, 0x9F00, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, + 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, + 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, + 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, + 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, + 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, + 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, + 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, + 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, + 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, + 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, + 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, + 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, + 0x6610, 0x6710, 0x6810, 0x6910, 0x6A10, 0x6B10, 0x6C10, 0x6D10, + 0x6E10, 0x6F10, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, + 0x7610, 0x7710, 0x7810, 0x7910, 0x7A10, 0x7B10, 0x7C10, 0x7D10, + 0x7E10, 0x7F10, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, + 0x8610, 0x8710, 0x8810, 0x8910, 0x8A10, 0x8B10, 0x8C10, 0x8D10, + 0x8E10, 0x8F10, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, + 0x9610, 0x9710, 0x9810, 0x9910, 0x9A10, 0x9B10, 0x9C10, 0x9D10, + 0x9E10, 0x9F10, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, + 0xA610, 0xA710, 0xA810, 0xA910, 0xAA10, 0xAB10, 0xAC10, 0xAD10, + 0xAE10, 0xAF10, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, + 0xB610, 0xB710, 0xB810, 0xB910, 0xBA10, 0xBB10, 0xBC10, 0xBD10, + 0xBE10, 0xBF10, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, + 0xC610, 0xC710, 0xC810, 0xC910, 0xCA10, 0xCB10, 0xCC10, 0xCD10, + 0xCE10, 0xCF10, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, + 0xD610, 0xD710, 0xD810, 0xD910, 0xDA10, 0xDB10, 0xDC10, 0xDD10, + 0xDE10, 0xDF10, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, + 0xE610, 0xE710, 0xE810, 0xE910, 0xEA10, 0xEB10, 0xEC10, 0xED10, + 0xEE10, 0xEF10, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, + 0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, 0xFC10, 0xFD10, + 0xFE10, 0xFF10, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, + 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, + 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, + 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, + 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, + 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, + 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, + 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, + 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, + 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, + 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, + 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, + 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, + 0x00C0, 0x0140, 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, + 0x0840, 0x0940, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, + 0x1040, 0x1140, 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, + 0x1840, 0x1940, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, + 0x2040, 0x2140, 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, + 0x2840, 0x2940, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, + 0x3040, 0x3140, 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, + 0x3840, 0x3940, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, + 0x4040, 0x4140, 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, + 0x4840, 0x4940, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, + 0x5040, 0x5140, 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, + 0x5840, 0x5940, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, + 0x6040, 0x6140, 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, + 0x6840, 0x6940, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, + 0x7040, 0x7140, 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, + 0x7840, 0x7940, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, + 0x8040, 0x8140, 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, + 0x8840, 0x8940, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, + 0x9040, 0x9140, 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740, + 0x9840, 0x9940, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, + 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, + 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, + 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, + 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, + 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, + 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, + 0xA050, 0xA150, 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, + 0xA850, 0xA950, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, + 0xB050, 0xB150, 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, + 0xB850, 0xB950, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, + 0xC050, 0xC150, 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, + 0xC850, 0xC950, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, + 0xD050, 0xD150, 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, + 0xD850, 0xD950, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, + 0xE050, 0xE150, 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, + 0xE850, 0xE950, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, + 0xF050, 0xF150, 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, + 0xF850, 0xF950, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, + 0x00D0, 0x0150, 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, + 0x0850, 0x0950, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, + 0x1050, 0x1150, 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, + 0x1850, 0x1950, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, + 0x2050, 0x2150, 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, + 0x2850, 0x2950, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, + 0x3050, 0x3150, 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, + 0x3850, 0x3950, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, + 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, + 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, + 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, + 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, + 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, + 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, + 0xFA60, 0xFB60, 0xFC60, 0xFD60, 0xFE60, 0xFF60, 0x00C0, 0x0140, + 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, + 0x0A60, 0x0B60, 0x0C60, 0x0D60, 0x0E60, 0x0F60, 0x1040, 0x1140, + 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, + 0x1A60, 0x1B60, 0x1C60, 0x1D60, 0x1E60, 0x1F60, 0x2040, 0x2140, + 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, + 0x2A60, 0x2B60, 0x2C60, 0x2D60, 0x2E60, 0x2F60, 0x3040, 0x3140, + 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, + 0x3A60, 0x3B60, 0x3C60, 0x3D60, 0x3E60, 0x3F60, 0x4040, 0x4140, + 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, + 0x4A60, 0x4B60, 0x4C60, 0x4D60, 0x4E60, 0x4F60, 0x5040, 0x5140, + 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, + 0x5A60, 0x5B60, 0x5C60, 0x5D60, 0x5E60, 0x5F60, 0x6040, 0x6140, + 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, + 0x6A60, 0x6B60, 0x6C60, 0x6D60, 0x6E60, 0x6F60, 0x7040, 0x7140, + 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, + 0x7A60, 0x7B60, 0x7C60, 0x7D60, 0x7E60, 0x7F60, 0x8040, 0x8140, + 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, + 0x8A60, 0x8B60, 0x8C60, 0x8D60, 0x8E60, 0x8F60, 0x9040, 0x9140, + 0x9240, 0x9340, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, + 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, + 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, + 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, + 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, + 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, + 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, + 0x9A70, 0x9B70, 0x9C70, 0x9D70, 0x9E70, 0x9F70, 0xA050, 0xA150, + 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, + 0xAA70, 0xAB70, 0xAC70, 0xAD70, 0xAE70, 0xAF70, 0xB050, 0xB150, + 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, + 0xBA70, 0xBB70, 0xBC70, 0xBD70, 0xBE70, 0xBF70, 0xC050, 0xC150, + 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, + 0xCA70, 0xCB70, 0xCC70, 0xCD70, 0xCE70, 0xCF70, 0xD050, 0xD150, + 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, + 0xDA70, 0xDB70, 0xDC70, 0xDD70, 0xDE70, 0xDF70, 0xE050, 0xE150, + 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, + 0xEA70, 0xEB70, 0xEC70, 0xED70, 0xEE70, 0xEF70, 0xF050, 0xF150, + 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, + 0xFA70, 0xFB70, 0xFC70, 0xFD70, 0xFE70, 0xFF70, 0x00D0, 0x0150, + 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, + 0x0A70, 0x0B70, 0x0C70, 0x0D70, 0x0E70, 0x0F70, 0x1050, 0x1150, + 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, + 0x1A70, 0x1B70, 0x1C70, 0x1D70, 0x1E70, 0x1F70, 0x2050, 0x2150, + 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, + 0x2A70, 0x2B70, 0x2C70, 0x2D70, 0x2E70, 0x2F70, 0x3050, 0x3150, + 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, + 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, + 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, + 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, + 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, + 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, + 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, +}; + +u8 ZeroTable[] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#define GBSAVE_GAME_VERSION_1 1 +#define GBSAVE_GAME_VERSION_2 2 +#define GBSAVE_GAME_VERSION_3 3 +#define GBSAVE_GAME_VERSION_4 4 +#define GBSAVE_GAME_VERSION_5 5 +#define GBSAVE_GAME_VERSION_6 6 +#define GBSAVE_GAME_VERSION_7 7 +#define GBSAVE_GAME_VERSION_8 8 +#define GBSAVE_GAME_VERSION_9 9 +#define GBSAVE_GAME_VERSION_10 10 +#define GBSAVE_GAME_VERSION_11 11 +#define GBSAVE_GAME_VERSION_12 12 +#define GBSAVE_GAME_VERSION_13 13 +#define GBSAVE_GAME_VERSION GBSAVE_GAME_VERSION_13 + +int inline gbGetValue(int min, int max, int v) +{ + return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0))); +} + +void gbGenFilter() +{ + for (int r = 0; r < 32; r++) + { + for (int g = 0; g < 32; g++) + { + for (int b = 0; b < 32; b++) + { + int nr = gbGetValue(gbGetValue(4, 14, g), + gbGetValue(24, 29, g), r) - 4; + int ng = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), + 14 + gbGetValue(0, 3, r), b), + gbGetValue(24 + gbGetValue(0, 3, r), + 29 + gbGetValue(0, 1, r), b), g) - 4; + int nb = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), + 14 + gbGetValue(0, 3, r), g), + gbGetValue(24 + gbGetValue(0, 3, r), + 29 + gbGetValue(0, 1, r), g), b) - 4; + gbColorFilter[(b << 10) | (g << 5) | r] = (nb << 10) | (ng << 5) | nr; + } + } + } +} + +void gbCopyMemory(u16 d, u16 s, int count) +{ + while (count) + { + gbWriteMemoryQuick(d, gbReadMemoryQuick(s)); + s++; + d++; + count--; + } +} + +void gbDoHdma() +{ + gbCopyMemory(gbHdmaDestination, gbHdmaSource, 0x10); + + gbHdmaDestination += 0x10; + gbHdmaSource += 0x10; + + register_HDMA2 = (register_HDMA2 + 0x10) & 0xFF; + if (register_HDMA2 == 0x00) + register_HDMA1++; + + register_HDMA4 = (register_HDMA4 + 0x10) & 0xFF; + if (register_HDMA4 == 0x00) + register_HDMA3++; + + if (gbHdmaDestination == 0x96b0) + gbHdmaBytes = gbHdmaBytes; + gbHdmaBytes -= 0x10; + register_HDMA5--; + if (register_HDMA5 == 0xff) + gbHdmaOn = 0; +} + +// fix for Harley and Lego Racers +void gbCompareLYToLYC() +{ + if (register_LY == register_LYC) + { + // mark that we have a match + register_STAT |= 4; + + // check if we need an interrupt + if ((register_STAT & 0x40) && (register_IE & 2)) + gbInterrupt |= 2; + } + else // no match + register_STAT &= 0xfb; +} + +// FIXME: horrible kludge to workaround the frame timing bug +static int32 s_gbJoymask[4] = { 0, 0, 0, 0 }; + +void gbWriteMemoryWrapped(register u16 address, register u8 value) +{ + if (address < 0x8000) + { +#ifndef FINAL_VERSION + if (memorydebug && (address > 0x3fff || address < 0x2000)) + { + log("Memory register write %04x=%02x PC=%04x\n", + address, + value, + PC.W); + } +#endif + if (mapper) + (*mapper)(address, value); + return; + } + + if (address < 0xa000) + { + gbWriteMemoryQuick(address, value); + return; + } + + if (address < 0xc000) + { +#ifndef FINAL_VERSION + if (memorydebug) + { + log("Memory register write %04x=%02x PC=%04x\n", + address, + value, + PC.W); + } +#endif + + if (mapper) + (*mapperRAM)(address, value); + return; + } + + if (address < 0xfe00) + { + gbWriteMemoryQuick(address, value); + return; + } + + if (address < 0xff00) + { + gbMemory[address] = value; + return; + } + + switch (address & 0x00ff) + { + case 0x00: + { + gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | + (value & 0x30)); + if (gbSgbMode) + { + gbSgbDoBitTransfer(value); + } + + return; + } + + case 0x01: + { + gbMemory[0xff01] = value; + return; + } + + // serial control + case 0x02: + { + gbSerialOn = (value & 0x80); + gbMemory[0xff02] = value; + if (gbSerialOn) + { + gbSerialTicks = GBSERIAL_CLOCK_TICKS; +#ifdef LINK_EMULATION + if (linkConnected) + { + if (value & 1) + { + linkSendByte(0x100 | gbMemory[0xFF01]); + Sleep(5); + } + } +#endif + } + + gbSerialBits = 0; + return; + } + + // DIV register resets on any write + case 0x04: + { + register_DIV = 0; + return; + } + case 0x05: + register_TIMA = value; + return; + + case 0x06: + register_TMA = value; + return; + + // TIMER control + case 0x07: + { + register_TAC = value; + + gbTimerOn = (value & 4); + gbTimerMode = value & 3; + // register_TIMA = register_TMA; + switch (gbTimerMode) + { + case 0: + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; + break; + case 1: + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_1_CLOCK_TICKS; + break; + case 2: + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_2_CLOCK_TICKS; + break; + case 3: + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_3_CLOCK_TICKS; + break; + } + return; + } + + case 0x0f: + { + register_IF = value; + gbInterrupt = value; + return; + } + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + { + SOUND_EVENT(address, value); + return; + } + case 0x40: + { + int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); + + if (lcdChange) + { + if (value & 0x80) + { + gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS; + gbLcdMode = 0; + register_STAT &= 0xfc; + register_LY = 0x00; + // FIXME: horrible workaround + if (gbNullInputHackTempEnabled && !useOldFrameTiming) + memcpy(gbJoymask, s_gbJoymask, sizeof(gbJoymask)); + } + else + { + gbLcdTicks = 0; + gbLcdMode = 0; + register_STAT &= 0xfc; + register_LY = 0x00; + // FIXME: horrible workaround + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); + if (gbNullInputHackTempEnabled && !useOldFrameTiming) + memset(gbJoymask, 0, sizeof(gbJoymask)); + } + // compareLYToLYC(); + } + // don't draw the window if it was not enabled and not being drawn before + if (!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 && + register_LY > register_WY) + gbWindowLine = 144; + + register_LCDC = value; + + return; + } + + // STAT + case 0x41: + { + //register_STAT = (register_STAT & 0x87) | + // (value & 0x7c); + register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? + // GB bug from Devrs FAQ + if (!gbCgbMode && (register_LCDC & 0x80) && gbLcdMode < 2) + gbInterrupt |= 2; + return; + } + + // SCY + case 0x42: + { + register_SCY = value; + return; + } + + // SCX + case 0x43: + { + register_SCX = value; + return; + } + + // LY + case 0x44: + { + // read only + return; + } + + // LYC + case 0x45: + { + register_LYC = value; + if ((register_LCDC & 0x80)) + { + gbCompareLYToLYC(); + } + return; + } + + // DMA! + case 0x46: + { + int source = value * 0x0100; + + gbCopyMemory(0xfe00, + source, + 0xa0); + register_DMA = value; + return; + } + + // BGP + case 0x47: + { + gbBgp[0] = value & 0x03; + gbBgp[1] = (value & 0x0c) >> 2; + gbBgp[2] = (value & 0x30) >> 4; + gbBgp[3] = (value & 0xc0) >> 6; + break; + } + + // OBP0 + case 0x48: + { + gbObp0[0] = value & 0x03; + gbObp0[1] = (value & 0x0c) >> 2; + gbObp0[2] = (value & 0x30) >> 4; + gbObp0[3] = (value & 0xc0) >> 6; + break; + } + + // OBP1 + case 0x49: + { + gbObp1[0] = value & 0x03; + gbObp1[1] = (value & 0x0c) >> 2; + gbObp1[2] = (value & 0x30) >> 4; + gbObp1[3] = (value & 0xc0) >> 6; + break; + } + + case 0x4a: + register_WY = value; + return; + + case 0x4b: + register_WX = value; + return; + + // KEY1 + case 0x4d: + { + if (gbCgbMode) + { + gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1); + return; + } + break; + } + + // VBK + case 0x4f: + { + if (gbCgbMode) + { + value = value & 1; + if (value == gbVramBank) + return; + + int vramAddress = value * 0x2000; + gbMemoryMap[0x08] = &gbVram[vramAddress]; + gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; + + gbVramBank = value; + register_VBK = value; + } + return; + break; + } + + // HDMA1 + case 0x51: + { + if (gbCgbMode) + { + if (value > 0x7f && value < 0xa0) + value = 0; + + gbHdmaSource = (value << 8) | (register_HDMA2 & 0xf0); + + register_HDMA1 = value; + return; + } + break; + } + + // HDMA2 + case 0x52: + { + if (gbCgbMode) + { + value = value & 0xf0; + + gbHdmaSource = (register_HDMA1 << 8) | (value); + + register_HDMA2 = value; + return; + } + break; + } + + // HDMA3 + case 0x53: + { + if (gbCgbMode) + { + value = value & 0x1f; + gbHdmaDestination = (value << 8) | (register_HDMA4 & 0xf0); + gbHdmaDestination += 0x8000; + register_HDMA3 = value; + return; + } + break; + } + + // HDMA4 + case 0x54: + { + if (gbCgbMode) + { + value = value & 0xf0; + gbHdmaDestination = ((register_HDMA3 & 0x1f) << 8) | value; + gbHdmaDestination += 0x8000; + register_HDMA4 = value; + return; + } + break; + } + + // HDMA5 + case 0x55: + { + if (gbCgbMode) + { + gbHdmaBytes = 16 + (value & 0x7f) * 16; + if (gbHdmaOn) + { + if (value & 0x80) + { + register_HDMA5 = (value & 0x7f); + } + else + { + register_HDMA5 = 0xff; + gbHdmaOn = 0; + } + } + else + { + if (value & 0x80) + { + gbHdmaOn = 1; + register_HDMA5 = value & 0x7f; + if (gbLcdMode == 0) + gbDoHdma(); + } + else + { + // we need to take the time it takes to complete the transfer into + // account... according to GB DEV FAQs, the setup time is the same + // for single and double speed, but the actual transfer takes the + // same time // (is that a typo?) + switch (gbDMASpeedVersion) + { + case 1: // I believe this is more correct + // the lower 7 bits of FF55 specify the Transfer Length (divided by 16, minus 1) + // and we make gbDmaTicks twice as many cycles at double speed to make the transfer take the same time + if (gbSpeed) + gbDmaTicks = 16 * ((value & 0x7f) + 1); + else + gbDmaTicks = 8 * ((value & 0x7f) + 1); + break; + case 0: // here for backward compatibility + // I think this was a guess that approximates the above in most but not all games + if (gbSpeed) + gbDmaTicks = 231 + 16 * (value & 0x7f); + else + gbDmaTicks = 231 + 8 * (value & 0x7f); + break; + default: // shouldn't happen + //assert(0); + break; + } + gbCopyMemory(gbHdmaDestination, gbHdmaSource, gbHdmaBytes); + gbHdmaDestination += gbHdmaBytes; + gbHdmaSource += gbHdmaBytes; + + register_HDMA3 = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; + register_HDMA4 = gbHdmaDestination & 0xf0; + register_HDMA1 = (gbHdmaSource >> 8) & 0xff; + register_HDMA2 = gbHdmaSource & 0xf0; + } + } + return; + } + break; + } + + // BCPS + case 0x68: + { + if (gbCgbMode) + { + int paletteIndex = (value & 0x3f) >> 1; + int paletteHiLo = (value & 0x01); + + gbMemory[0xff68] = value; + gbMemory[0xff69] = (paletteHiLo ? + (gbPalette[paletteIndex] >> 8) : + (gbPalette[paletteIndex] & 0x00ff)); + return; + } + break; + } + + // BCPD + case 0x69: + { + if (gbCgbMode) + { + int v = gbMemory[0xff68]; + int paletteIndex = (v & 0x3f) >> 1; + int paletteHiLo = (v & 0x01); + gbMemory[0xff69] = value; + gbPalette[paletteIndex] = (paletteHiLo ? + ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : + ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; + + if (gbMemory[0xff68] & 0x80) + { + int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f; + + gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index; + + gbMemory[0xff69] = (index & 1 ? + (gbPalette[index >> 1] >> 8) : + (gbPalette[index >> 1] & 0x00ff)); + } + return; + } + break; + } + + // OCPS + case 0x6a: + { + if (gbCgbMode) + { + int paletteIndex = (value & 0x3f) >> 1; + int paletteHiLo = (value & 0x01); + + paletteIndex += 32; + + gbMemory[0xff6a] = value; + gbMemory[0xff6b] = (paletteHiLo ? + (gbPalette[paletteIndex] >> 8) : + (gbPalette[paletteIndex] & 0x00ff)); + return; + } + break; + } + + // OCPD + case 0x6b: + { + if (gbCgbMode) + { + int v = gbMemory[0xff6a]; + int paletteIndex = (v & 0x3f) >> 1; + int paletteHiLo = (v & 0x01); + + paletteIndex += 32; + + gbMemory[0xff6b] = value; + gbPalette[paletteIndex] = (paletteHiLo ? + ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : + ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; + if (gbMemory[0xff6a] & 0x80) + { + int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f; + + gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index; + + gbMemory[0xff6b] = (index & 1 ? + (gbPalette[(index >> 1) + 32] >> 8) : + (gbPalette[(index >> 1) + 32] & 0x00ff)); + } + return; + } + break; + } + + // SVBK + case 0x70: + { + if (gbCgbMode) + { + value = value & 7; + + int bank = value; + if (value == 0) + bank = 1; + + if (bank == gbWramBank) + return; + + int wramAddress = bank * 0x1000; + gbMemoryMap[0x0d] = &gbWram[wramAddress]; + + gbWramBank = bank; + register_SVBK = value; + return; + } + break; + } + + case 0xff: + { + register_IE = value; + register_IF &= value; + return; + } + } + + gbWriteMemoryQuick(address, value); +} + +u8 gbReadOpcode(register u16 address) +{ + if (gbCheatMap[address]) + return gbCheatRead(address); + + // the following fix does more than Echo RAM fix, anyway... + switch (gbEchoRAMFixOn ? (address >> 12) & 0x000f : address & 0xf000) + { + case 0x0a: + case 0x0b: + if (mapperReadRAM) + return mapperReadRAM(address); + break; + case 0x0f: + if (address > 0xff00) + { + switch (address & 0x00ff) + { + case 0x04: + return register_DIV; + case 0x05: + return register_TIMA; + case 0x06: + return register_TMA; + case 0x07: + return (0xf8 | register_TAC); + case 0x0f: + return (0xe0 | register_IF); + case 0x40: + return register_LCDC; + case 0x41: + return (0x80 | register_STAT); + case 0x42: + return register_SCY; + case 0x43: + return register_SCX; + case 0x44: + return register_LY; + case 0x45: + return register_LYC; + case 0x46: + return register_DMA; + case 0x4a: + return register_WY; + case 0x4b: + return register_WX; + case 0x4f: + return (0xfe | register_VBK); + case 0x51: + return register_HDMA1; + case 0x52: + return register_HDMA2; + case 0x53: + return register_HDMA3; + case 0x54: + return register_HDMA4; + case 0x55: + return register_HDMA5; + case 0x70: + return (0xf8 | register_SVBK); + case 0xff: + return register_IE; + } + } + break; + } + return gbReadMemoryQuick(address); +} + +void gbWriteMemory(register u16 address, register u8 value) +{ + gbWriteMemoryWrapped(address, value); + CallRegisteredLuaMemHook(address, 1, value, LUAMEMHOOK_WRITE); +} + +u8 gbReadMemory(register u16 address) +{ + if (gbCheatMap[address]) + return gbCheatRead(address); + + if (address < 0xa000) + return gbReadMemoryQuick(address); + + if (address < 0xc000) + { +#ifndef FINAL_VERSION + if (memorydebug) + { + log("Memory register read %04x PC=%04x\n", + address, + PC.W); + } +#endif + + if (mapperReadRAM) + return mapperReadRAM(address); + return gbReadMemoryQuick(address); + } + + if (address >= 0xff00) + { + switch (address & 0x00ff) + { + case 0x00: + { + if (gbSgbMode) + { + gbSgbReadingController |= 4; + gbSgbResetPacketState(); + } + + int b = gbMemory[0xff00]; + + if ((b & 0x30) == 0x20) + { + b &= 0xf0; + + int joy = 0; + if (gbSgbMode && gbSgbMultiplayer) + { + switch (gbSgbNextController) + { + case 0x0f: + joy = 0; + break; + case 0x0e: + joy = 1; + break; + case 0x0d: + joy = 2; + break; + case 0x0c: + joy = 3; + break; + default: + joy = 0; + } + } + int joystate = gbJoymask[joy]; + if (!(joystate & 128)) + b |= 0x08; + if (!(joystate & 64)) + b |= 0x04; + if (!(joystate & 32)) + b |= 0x02; + if (!(joystate & 16)) + b |= 0x01; + + gbMemory[0xff00] = b; + } + else if ((b & 0x30) == 0x10) + { + b &= 0xf0; + + int joy = 0; + if (gbSgbMode && gbSgbMultiplayer) + { + switch (gbSgbNextController) + { + case 0x0f: + joy = 0; + break; + case 0x0e: + joy = 1; + break; + case 0x0d: + joy = 2; + break; + case 0x0c: + joy = 3; + break; + default: + joy = 0; + } + } + int joystate = gbJoymask[joy]; + if (!(joystate & 8)) + b |= 0x08; + if (!(joystate & 4)) + b |= 0x04; + if (!(joystate & 2)) + b |= 0x02; + if (!(joystate & 1)) + b |= 0x01; + + gbMemory[0xff00] = b; + } + else + { + if (gbSgbMode && gbSgbMultiplayer) + { + gbMemory[0xff00] = 0xf0 | gbSgbNextController; + } + else + { + gbMemory[0xff00] = 0xff; + } + } + } + GBSystemCounters.lagged = false; + return gbMemory[0xff00]; + break; + case 0x01: + return gbMemory[0xff01]; + case 0x04: + return register_DIV; + case 0x05: + return register_TIMA; + case 0x06: + return register_TMA; + case 0x07: + return (0xf8 | register_TAC); + case 0x0f: + return (0xe0 | register_IF); + case 0x40: + return register_LCDC; + case 0x41: + return (0x80 | register_STAT); + case 0x42: + return register_SCY; + case 0x43: + return register_SCX; + case 0x44: + return register_LY; + case 0x45: + return register_LYC; + case 0x46: + return register_DMA; + case 0x4a: + return register_WY; + case 0x4b: + return register_WX; + case 0x4f: + return (0xfe | register_VBK); + case 0x51: + return register_HDMA1; + case 0x52: + return register_HDMA2; + case 0x53: + return register_HDMA3; + case 0x54: + return register_HDMA4; + case 0x55: + return register_HDMA5; + case 0x70: + return (0xf8 | register_SVBK); + case 0xff: + return register_IE; + } + } + + return gbReadMemoryQuick(address); +} + +void gbVblank_interrupt() +{ + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + gbInterrupt &= 0xfe; + + IFF &= 0x7e; + register_IF &= 0xfe; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x40; +} + +void gbLcd_interrupt() +{ + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + gbInterrupt &= 0xfd; + IFF &= 0x7e; + register_IF &= 0xfd; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + + PC.W = 0x48; +} + +void gbTimer_interrupt() +{ + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + IFF &= 0x7e; + gbInterrupt &= 0xfb; + register_IF &= 0xfb; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + + PC.W = 0x50; +} + +void gbSerial_interrupt() +{ + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + IFF &= 0x7e; + gbInterrupt &= 0xf7; + register_IF &= 0xf7; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + + PC.W = 0x58; +} + +void gbJoypad_interrupt() +{ + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + IFF &= 0x7e; + gbInterrupt &= 0xef; + register_IF &= 0xef; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + + PC.W = 0x60; +} + +void gbSpeedSwitch() +{ + if (gbSpeed == 0) + { + gbSpeed = 1; + GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; //127; //51 * 2; + GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; + GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; //52; //20 * 2; + GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; //99; //43 * 2; + GBDIV_CLOCK_TICKS = 64 * 2; + GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; + GBTIMER_MODE_0_CLOCK_TICKS = 256; //256*2; + GBTIMER_MODE_1_CLOCK_TICKS = 4; //4*2; + GBTIMER_MODE_2_CLOCK_TICKS = 16; //16*2; + GBTIMER_MODE_3_CLOCK_TICKS = 64; //64*2; + GBSERIAL_CLOCK_TICKS = 128 * 2; + gbDivTicks *= 2; + gbLcdTicks *= 2; + gbLcdLYIncrementTicks *= 2; + // timerTicks *= 2; + // timerClockTicks *= 2; + gbSerialTicks *= 2; + SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS * 2; + soundTicks *= 2; + // synchronizeTicks *= 2; + // SYNCHRONIZE_CLOCK_TICKS *= 2; + } + else + { + gbSpeed = 0; + GBLCD_MODE_0_CLOCK_TICKS = 51; + GBLCD_MODE_1_CLOCK_TICKS = 1140; + GBLCD_MODE_2_CLOCK_TICKS = 20; + GBLCD_MODE_3_CLOCK_TICKS = 43; + GBDIV_CLOCK_TICKS = 64; + GBLY_INCREMENT_CLOCK_TICKS = 114; + GBTIMER_MODE_0_CLOCK_TICKS = 256; + GBTIMER_MODE_1_CLOCK_TICKS = 4; + GBTIMER_MODE_2_CLOCK_TICKS = 16; + GBTIMER_MODE_3_CLOCK_TICKS = 64; + GBSERIAL_CLOCK_TICKS = 128; + gbDivTicks /= 2; + gbLcdTicks /= 2; + gbLcdLYIncrementTicks /= 2; + // timerTicks /= 2; + // timerClockTicks /= 2; + gbSerialTicks /= 2; + SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS; + soundTicks /= 2; + // synchronizeTicks /= 2; + // SYNCHRONIZE_CLOCK_TICKS /= 2; + } +} + +void gbGetHardwareType() +{ + gbCgbMode = 0; + if (gbRom[0x143] & 0x80) + { + if (gbEmulatorType == 0 || + gbEmulatorType == 1 || + gbEmulatorType == 4 || + gbEmulatorType == 5 || + (gbRom[0x146] != 0x03 && (gbEmulatorType == 2))) + { + gbCgbMode = 1; + } + } + + if (gbSgbMode == 2) + { + gbSgbMode = 0; + return; + } + + gbSgbMode = 0; + if (gbRom[0x146] == 0x03) + { + if (gbEmulatorType == 0 || + gbEmulatorType == 2 || + gbEmulatorType == 5 || + (!(gbRom[0x143] & 0x80) && (gbEmulatorType == 1 || gbEmulatorType == 4))) + gbSgbMode = 1; + } +} + +void gbReset(bool userReset) +{ + // movie must be closed while opening/creating a movie + if (userReset && VBAMovieRecording()) + { + VBAMovieSignalReset(); + return; + } + + if (!VBAMovieActive()) + { + GBSystemCounters.frameCount = 0; + GBSystemCounters.lagCount = 0; + GBSystemCounters.extraCount = 0; + GBSystemCounters.lagged = true; + GBSystemCounters.laggedLast = true; + } + + SP.W = 0xfffe; + AF.W = 0x01b0; + BC.W = 0x0013; + DE.W = 0x00d8; + HL.W = 0x014d; + PC.W = 0x0100; + IFF = 0; + gbInterrupt = 1; + gbInterruptWait = 0; + + register_DIV = 0; + register_TIMA = 0; + register_TMA = 0; + register_TAC = 0; + register_IF = 1; + register_LCDC = 0x91; + register_STAT = 0; + register_SCY = 0; + register_SCX = 0; + register_LY = 0; + register_LYC = 0; + register_DMA = 0; + register_WY = 0; + register_WX = 0; + register_VBK = 0; + register_HDMA1 = 0; + register_HDMA2 = 0; + register_HDMA3 = 0; + register_HDMA4 = 0; + register_HDMA5 = 0; + register_SVBK = 0; + register_IE = 0; + + gbGetHardwareType(); + if (gbCgbMode) + { + if (!gbVram) + gbVram = (u8 *)malloc(0x4000 + 4); + if (!gbWram) + gbWram = (u8 *)malloc(0x8000 + 4); + memset(gbVram, 0, 0x4000 + 4); + memset(gbWram, 0, 0x8000 + 4); + } + else + { + if (gbVram) + { + free(gbVram); + gbVram = NULL; + } + if (gbWram) + { + free(gbWram); + gbWram = NULL; + } + } + + // clean LineBuffer + if (gbLineBuffer) + memset(gbLineBuffer, 0, 160 * sizeof(u16)); + // clean Pix + if (pix) + memset(pix, 0, 4 * 257 * 226); + + if (gbCgbMode) + { + if (gbSgbMode) + { + if (gbEmulatorType == 5) + AF.W = 0xffb0; + else + AF.W = 0x01b0; + BC.W = 0x0013; + DE.W = 0x00d8; + HL.W = 0x014d; + } + else + { + AF.W = 0x11b0; + BC.W = 0x0000; + DE.W = 0xff56; + HL.W = 0x000d; + } + if (gbEmulatorType == 4) + BC.B.B1 |= 0x01; + + register_HDMA5 = 0xff; + gbMemory[0xff68] = 0xc0; + gbMemory[0xff6a] = 0xc0; + + for (int i = 0; i < 64; i++) + gbPalette[i] = 0x7fff; + } + else + { + for (int i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; + } + + if (gbSpeed) + { + gbSpeedSwitch(); + gbMemory[0xff4d] = 0; + } + + gbDivTicks = GBDIV_CLOCK_TICKS; + gbLcdMode = 2; + gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS; + gbLcdLYIncrementTicks = 0; + gbTimerTicks = 0; + gbTimerClockTicks = 0; + gbSerialTicks = 0; + gbSerialBits = 0; + gbSerialOn = 0; + gbWindowLine = -1; + gbTimerOn = 0; + gbTimerMode = 0; + // gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS; + gbSpeed = 0; + gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; + + // FIXME: horrible kludge + memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); + + if (gbCgbMode) + { + gbSpeed = 0; + gbHdmaOn = 0; + gbHdmaSource = 0x0000; + gbHdmaDestination = 0x8000; + gbVramBank = 0; + gbWramBank = 1; + register_LY = 0x90; + gbLcdMode = 1; + } + + if (gbSgbMode) + { + gbSgbReset(); + } + + for (int i = 0; i < 4; i++) + gbBgp[i] = gbObp0[i] = gbObp1[i] = i; + + memset(&gbDataMBC1, 0, sizeof(gbDataMBC1)); + gbDataMBC1.mapperROMBank = 1; + + gbDataMBC2.mapperRAMEnable = 0; + gbDataMBC2.mapperROMBank = 1; + + memset(&gbDataMBC3, 0, 6 * sizeof(int32)); + gbDataMBC3.mapperROMBank = 1; + + memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); + gbDataMBC5.mapperROMBank = 1; + switch (gbRom[0x147]) + { + case 0x1c: + case 0x1d: + case 0x1e: + gbDataMBC5.isRumbleCartridge = 1; + } + + memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); + gbDataHuC1.mapperROMBank = 1; + + memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); + gbDataHuC3.mapperROMBank = 1; + + gbMemoryMap[0x00] = &gbRom[0x0000]; + gbMemoryMap[0x01] = &gbRom[0x1000]; + gbMemoryMap[0x02] = &gbRom[0x2000]; + gbMemoryMap[0x03] = &gbRom[0x3000]; + gbMemoryMap[0x04] = &gbRom[0x4000]; + gbMemoryMap[0x05] = &gbRom[0x5000]; + gbMemoryMap[0x06] = &gbRom[0x6000]; + gbMemoryMap[0x07] = &gbRom[0x7000]; + if (gbCgbMode) + { + gbMemoryMap[0x08] = &gbVram[0x0000]; + gbMemoryMap[0x09] = &gbVram[0x1000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbWram[0x1000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + } + else + { + gbMemoryMap[0x08] = &gbMemory[0x8000]; + gbMemoryMap[0x09] = &gbMemory[0x9000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbMemory[0xd000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + } + + if (gbRam) + { + gbMemoryMap[0x0a] = &gbRam[0x0000]; + gbMemoryMap[0x0b] = &gbRam[0x1000]; + } + + gbSoundReset(); + + systemResetSensor(); + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + gbLastTime = systemGetClock(); + gbFrameCount = 0; + + systemRefreshScreen(); +} + +void gbWriteSaveMBC1(const char *name) +{ + FILE *gzFile = fopen(name, "wb"); + + if (gzFile == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + gbRamSize, + gzFile); + + fclose(gzFile); +} + +void gbWriteSaveMBC2(const char *name) +{ + FILE *file = fopen(name, "wb"); + + if (file == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(&gbMemory[0xa000], + 1, + 256, + file); + + fclose(file); +} + +void gbWriteSaveMBC3(const char *name, bool extendedSave) +{ + FILE *gzFile = fopen(name, "wb"); + + if (gzFile == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + gbRamSize, + gzFile); + + if (extendedSave) + { + //assert(sizeof(time_t) == 4); + fwrite(&gbDataMBC3.mapperSeconds, + 1, + 10 * sizeof(int32) + /*sizeof(time_t)*/4, + gzFile); + } + + fclose(gzFile); +} + +void gbWriteSaveMBC5(const char *name) +{ + FILE *gzFile = fopen(name, "wb"); + + if (gzFile == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + gbRamSize, + gzFile); + + fclose(gzFile); +} + +void gbWriteSaveMBC7(const char *name) +{ + FILE *file = fopen(name, "wb"); + + if (file == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(&gbMemory[0xa000], + 1, + 256, + file); + + fclose(file); +} + +bool gbReadSaveMBC1(const char *name) +{ + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) + { + return false; + } + + int read = gzread(gzFile, + gbRam, + gbRamSize); + + if (read != gbRamSize) + { + systemMessage(MSG_FAILED_TO_READ_SGM, N_("Failed to read complete save game %s (%d)"), name, read); + gzclose(gzFile); + return false; + } + + gzclose(gzFile); + return true; +} + +bool gbReadSaveMBC2(const char *name) +{ + FILE *file = fopen(name, "rb"); + + if (file == NULL) + { + return false; + } + + int read = fread(&gbMemory[0xa000], + 1, + 256, + file); + + if (read != 256) + { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Failed to read complete save game %s (%d)"), name, read); + fclose(file); + return false; + } + + fclose(file); + return true; +} + +bool gbReadSaveMBC3(const char *name) +{ + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) + { + return false; + } + + int read = gzread(gzFile, + gbRam, + gbRamSize); + + bool res = true; + + if (read != gbRamSize) + { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Failed to read complete save game %s (%d)"), name, read); + } + else + { + //assert(sizeof(time_t) == 4); + read = gzread(gzFile, + &gbDataMBC3.mapperSeconds, + sizeof(int32) * 10 + /*sizeof(time_t)*/4); + + if (read != (sizeof(int32) * 10 + /*sizeof(time_t)*/4) && read != 0) + { + systemMessage(MSG_FAILED_TO_READ_RTC, + N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } + } + + gzclose(gzFile); + return res; +} + +bool gbReadSaveMBC5(const char *name) +{ + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) + { + return false; + } + + int read = gzread(gzFile, + gbRam, + gbRamSize); + + if (read != gbRamSize) + { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Failed to read complete save game %s (%d)"), name, read); + gzclose(gzFile); + return false; + } + + gzclose(gzFile); + return true; +} + +bool gbReadSaveMBC7(const char *name) +{ + FILE *file = fopen(name, "rb"); + + if (file == NULL) + { + return false; + } + + int read = fread(&gbMemory[0xa000], + 1, + 256, + file); + + if (read != 256) + { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Failed to read complete save game %s (%d)"), name, read); + fclose(file); + return false; + } + + fclose(file); + return true; +} + +#if 0 +bool gbLoadBIOS(const char *biosFileName, bool useBiosFile) +{ + useBios = false; + if (useBiosFile) + { + useBios = utilLoadBIOS(bios, biosFileName, gbEmulatorType); + if (!useBios) + { + systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file")); + } + } + return useBios; +} +#endif + +void gbInit() +{ + gbGenFilter(); + gbSgbInit(); // calls gbSgbReset()... whatever + + gbMemory = (u8 *)malloc(65536 + 4); + memset(gbMemory, 0, 65536 + 4); + memset(gbPalette, 0, 2 * 128); + + // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel + origPix = (u8 *)calloc(1, 4 * 257 * 226 + 4); + pix = origPix + 4; + + gbLineBuffer = (u16 *)malloc(160 * sizeof(u16)); +} + +bool gbWriteBatteryFile(const char *file, bool extendedSave) +{ + if (gbBattery) + { + int type = gbRom[0x147]; + + switch (type) + { + case 0x03: + gbWriteSaveMBC1(file); + break; + case 0x06: + gbWriteSaveMBC2(file); + break; + case 0x0f: + case 0x10: + case 0x13: + gbWriteSaveMBC3(file, extendedSave); + break; + case 0x1b: + case 0x1e: + gbWriteSaveMBC5(file); + break; + case 0x22: + gbWriteSaveMBC7(file); + break; + case 0xff: + gbWriteSaveMBC1(file); + break; + } + } + return true; +} + +bool gbWriteBatteryFile(const char *file) +{ + gbWriteBatteryFile(file, true); + return true; +} + +bool gbWriteBatteryToStream(gzFile gzfile) +{ + // the GB save code is ugly, so rather than convert it all to use gzFiles, just save it to a temp file... +#define TEMP_SAVE_FNAME ("tempvbawrite.sav") + bool retVal = gbWriteBatteryFile(TEMP_SAVE_FNAME, true); + + // ...open the temp file and figure out its size... + FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "rb"); + if (fileTemp == NULL) + return false; + fseek(fileTemp, 0, SEEK_END); + int len = (int) ftell(fileTemp); + + // ...copy over the temp file... + char *temp = new char [len]; + fseek(fileTemp, 0, SEEK_SET); + if (fread(temp, len, 1, fileTemp) != 1) + { + delete [] temp; + fclose(fileTemp); + return false; + } + fclose(fileTemp); + utilGzWrite(gzfile, temp, len); + delete [] temp; + + // ... and delete the temp file + remove(TEMP_SAVE_FNAME); +#undef TEMP_SAVE_FNAME + + return retVal; +} + +bool gbReadBatteryFile(const char *file) +{ + bool res = false; + if (gbBattery) + { + int type = gbRom[0x147]; + + switch (type) + { + case 0x03: + res = gbReadSaveMBC1(file); + break; + case 0x06: + res = gbReadSaveMBC2(file); + break; + case 0x0f: + case 0x10: + case 0x13: + if (!gbReadSaveMBC3(file)) + { + struct tm *lt; + time_t tmp; //Small kludge to get it working on some systems where time_t has size 8. + + if (VBAMovieActive() || VBAMovieLoading()) + { + gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter() / 60; + lt = gmtime(&tmp); + gbDataMBC3.mapperLastTime=(u32)tmp; + } + else + { + time(&tmp); + gbDataMBC3.mapperLastTime=(u32)tmp; + lt = localtime(&tmp); + } + systemScreenMessage(ctime(&tmp), 4); + gbDataMBC3.mapperLastTime=(u32)tmp; + + gbDataMBC3.mapperSeconds = lt->tm_sec; + gbDataMBC3.mapperMinutes = lt->tm_min; + gbDataMBC3.mapperHours = lt->tm_hour; + gbDataMBC3.mapperDays = lt->tm_yday & 255; + gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | + (lt->tm_yday > 255 ? 1 : 0); + res = false; + break; + } + time_t tmp; + systemScreenMessage(ctime(&tmp), 4); + gbDataMBC3.mapperLastTime=(u32)tmp; + res = true; + break; + case 0x1b: + case 0x1e: + res = gbReadSaveMBC5(file); + break; + case 0x22: + res = gbReadSaveMBC7(file); + case 0xff: + res = gbReadSaveMBC1(file); + break; + } + } + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + return res; +} + +bool gbReadBatteryFromStream(gzFile gzfile) +{ + // the GB save code is ugly, so rather than convert it all to use gzFiles, just copy it to temp RAM... +#define TEMP_SAVE_FNAME ("tempvbaread.sav") + int pos = gztell(gzfile); + int buflen = 1024; + // ...make a temp file and write it there... + FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "wb"); + if (fileTemp == NULL) + return false; + int gzDeflated; + char *temp = new char [buflen]; + while ((gzDeflated = utilGzRead(gzfile, temp, buflen)) != 0) + { + if (gzDeflated == -1 || fwrite(temp, gzDeflated, 1, fileTemp) != 1) + { + delete [] temp; + fclose(fileTemp); + gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that + // calls this right now does a seek afterwards so it doesn't matter for now, but it's + // still bad) + return false; + } + } + gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that calls this + // right now does a seek afterwards so it doesn't matter for now, but it's still bad) + fclose(fileTemp); + delete [] temp; + + // ... load from the temp file... + bool retVal = gbReadBatteryFile(TEMP_SAVE_FNAME); + + // ... and delete the temp file + remove(TEMP_SAVE_FNAME); +#undef TEMP_SAVE_FNAME + + return retVal; +} + +bool gbReadGSASnapshot(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if (!file) + { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + return false; + } + + // long size = ftell(file); + fseek(file, 0x4, SEEK_SET); + char buffer[16]; + char buffer2[16]; + fread(buffer, 1, 15, file); + buffer[15] = 0; + memcpy(buffer2, &gbRom[0x134], 15); + buffer2[15] = 0; + if (memcmp(buffer, buffer2, 15)) + { + systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, + N_("Cannot import snapshot for %s. Current game is %s"), + buffer, + buffer2); + fclose(file); + return false; + } + fseek(file, 0x13, SEEK_SET); + int read = 0; + int toRead = 0; + switch (gbRom[0x147]) + { + case 0x03: + case 0x0f: + case 0x10: + case 0x13: + case 0x1b: + case 0x1e: + case 0xff: + read = fread(gbRam, 1, gbRamSize, file); + toRead = gbRamSize; + break; + case 0x06: + case 0x22: + read = fread(&gbMemory[0xa000], 1, 256, file); + toRead = 256; + break; + default: + systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, + N_("Unsupported snapshot file %s"), + fileName); + fclose(file); + return false; + } + fclose(file); + gbReset(); + return true; +} + +variable_desc gbSaveGameStruct[] = +{ + { &PC.W, sizeof(u16) }, + { &SP.W, sizeof(u16) }, + { &AF.W, sizeof(u16) }, + { &BC.W, sizeof(u16) }, + { &DE.W, sizeof(u16) }, + { &HL.W, sizeof(u16) }, + { &IFF, sizeof(u8) }, + { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int32) }, + { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int32) }, + { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int32) }, + { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int32) }, + { &GBDIV_CLOCK_TICKS, sizeof(int32) }, + { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int32) }, + { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int32) }, + { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int32) }, + { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int32) }, + { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int32) }, + { &GBSERIAL_CLOCK_TICKS, sizeof(int32) }, + { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int32) }, + { &gbDivTicks, sizeof(int32) }, + { &gbLcdMode, sizeof(int32) }, + { &gbLcdTicks, sizeof(int32) }, + { &gbLcdLYIncrementTicks, sizeof(int32) }, + { &gbTimerTicks, sizeof(int32) }, + { &gbTimerClockTicks, sizeof(int32) }, + { &gbSerialTicks, sizeof(int32) }, + { &gbSerialBits, sizeof(int32) }, + { &gbInterrupt, sizeof(int32) }, + { &gbInterruptWait, sizeof(int32) }, + { &gbSynchronizeTicks, sizeof(int32) }, + { &gbTimerOn, sizeof(int32) }, + { &gbTimerMode, sizeof(int32) }, + { &gbSerialOn, sizeof(int32) }, + { &gbWindowLine, sizeof(int32) }, + { &gbCgbMode, sizeof(int32) }, + { &gbVramBank, sizeof(int32) }, + { &gbWramBank, sizeof(int32) }, + { &gbHdmaSource, sizeof(int32) }, + { &gbHdmaDestination, sizeof(int32) }, + { &gbHdmaBytes, sizeof(int32) }, + { &gbHdmaOn, sizeof(int32) }, + { &gbSpeed, sizeof(int32) }, + { &gbSgbMode, sizeof(int32) }, + { ®ister_DIV, sizeof(u8) }, + { ®ister_TIMA, sizeof(u8) }, + { ®ister_TMA, sizeof(u8) }, + { ®ister_TAC, sizeof(u8) }, + { ®ister_IF, sizeof(u8) }, + { ®ister_LCDC, sizeof(u8) }, + { ®ister_STAT, sizeof(u8) }, + { ®ister_SCY, sizeof(u8) }, + { ®ister_SCX, sizeof(u8) }, + { ®ister_LY, sizeof(u8) }, + { ®ister_LYC, sizeof(u8) }, + { ®ister_DMA, sizeof(u8) }, + { ®ister_WY, sizeof(u8) }, + { ®ister_WX, sizeof(u8) }, + { ®ister_VBK, sizeof(u8) }, + { ®ister_HDMA1, sizeof(u8) }, + { ®ister_HDMA2, sizeof(u8) }, + { ®ister_HDMA3, sizeof(u8) }, + { ®ister_HDMA4, sizeof(u8) }, + { ®ister_HDMA5, sizeof(u8) }, + { ®ister_SVBK, sizeof(u8) }, + { ®ister_IE, sizeof(u8) }, + { &gbBgp[0], sizeof(u8) }, + { &gbBgp[1], sizeof(u8) }, + { &gbBgp[2], sizeof(u8) }, + { &gbBgp[3], sizeof(u8) }, + { &gbObp0[0], sizeof(u8) }, + { &gbObp0[1], sizeof(u8) }, + { &gbObp0[2], sizeof(u8) }, + { &gbObp0[3], sizeof(u8) }, + { &gbObp1[0], sizeof(u8) }, + { &gbObp1[1], sizeof(u8) }, + { &gbObp1[2], sizeof(u8) }, + { &gbObp1[3], sizeof(u8) }, + { NULL, 0 } +}; + +bool gbWriteSaveStateToStream(gzFile gzFile) +{ + utilWriteInt(gzFile, GBSAVE_GAME_VERSION); + + utilGzWrite(gzFile, &gbRom[0x134], 15); + + utilWriteData(gzFile, gbSaveGameStruct); + + utilGzWrite(gzFile, &IFF, 2); + + if (gbSgbMode) + { + gbSgbSaveGame(gzFile); + } + + utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); + utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); + //assert(sizeof(time_t) == 4); + utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); + utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); + utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); + utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); + + // yes, this definitely needs to be saved, or loading paused games will show a black screen + // this is also necessary to be consistent with what the GBA saving does + utilGzWrite(gzFile, pix, 4 * 257 * 226); + + utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); + // todo: remove + utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); + + utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); + + if (gbRamSize && gbRam) + { + utilGzWrite(gzFile, gbRam, gbRamSize); + } + + if (gbCgbMode) + { + utilGzWrite(gzFile, gbVram, 0x4000); + utilGzWrite(gzFile, gbWram, 0x8000); + } + + gbSoundSaveGame(gzFile); + + gbCheatsSaveGame(gzFile); + + // new to re-recording version: + { + extern int32 sensorX, sensorY; + utilGzWrite(gzFile, &sensorX, sizeof(sensorX)); + utilGzWrite(gzFile, &sensorY, sizeof(sensorY)); + utilGzWrite(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get + // carried + // back on loading a snapshot! + + bool8 movieActive = VBAMovieActive(); + utilGzWrite(gzFile, &movieActive, sizeof(movieActive)); + if (movieActive) + { + uint8 *movie_freeze_buf = NULL; + uint32 movie_freeze_size = 0; + + VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size); + if (movie_freeze_buf) + { + utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size)); + utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size); + delete [] movie_freeze_buf; + } + else + { + systemMessage(0, N_("Failed to save movie snapshot.")); + return false; + } + } + utilGzWrite(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); + } + + // new to rerecording 19.4 wip (svn r22+): + { + utilGzWrite(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); + utilGzWrite(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); + utilGzWrite(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); + } + + return true; +} + +bool gbWriteMemSaveState(char *memory, int available) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "w"); + + if (gzFile == NULL) + { + return false; + } + + bool res = gbWriteSaveStateToStream(gzFile); + + long pos = utilGzTell(gzFile) + 8; + + if (pos >= (available)) + res = false; + + utilGzClose(gzFile); + + return res; +} + +bool gbWriteSaveState(const char *name) +{ + gzFile gzFile = utilGzOpen(name, "wb"); + + if (gzFile == NULL) + return false; + + bool res = gbWriteSaveStateToStream(gzFile); + + utilGzClose(gzFile); + return res; +} + +static int tempStateID = 0; +static int tempFailCount = 0; +static bool backupSafe = true; + +bool gbReadSaveStateFromStream(gzFile gzFile) +{ + int type; + char tempBackupName [128]; + if (backupSafe) + { + sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++); + gbWriteSaveState(tempBackupName); + } + + int version = utilReadInt(gzFile); + + if (version > GBSAVE_GAME_VERSION || version < 0) + { + systemMessage(MSG_UNSUPPORTED_VB_SGM, + N_("Unsupported VisualBoy save game version %d"), version); + goto failedLoadGB; + } + + u8 romname[20]; + + utilGzRead(gzFile, romname, 15); + + if (memcmp(&gbRom[0x134], romname, 15) != 0) + { + systemMessage(MSG_CANNOT_LOAD_SGM_FOR, + N_("Cannot load save game for %s. Playing %s"), + romname, &gbRom[0x134]); + goto failedLoadGB; + } + + utilReadData(gzFile, gbSaveGameStruct); + + if (version >= GBSAVE_GAME_VERSION_7) + { + utilGzRead(gzFile, &IFF, 2); + } + + if (gbSgbMode) + { + gbSgbReadGame(gzFile, version); + } + else + { + gbSgbMask = 0; // loading a game at the wrong time causes no display + } + + utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); + utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); + if (version < GBSAVE_GAME_VERSION_4) + // prior to version 4, there was no adjustment for the time the game + // was last played, so we have less to read. This needs update if the + // structure changes again. + utilGzRead(gzFile, &gbDataMBC3, sizeof(int32) * 10); + else + { + //assert(sizeof(time_t) == 4); + utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); + } + utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); + utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); + utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); + + if (version >= GBSAVE_GAME_VERSION_12) + { + utilGzRead(gzFile, pix, 4 * 257 * 226); + } + else + { + memset(pix, 0, 257 * 226 * sizeof(u32)); +// if(version < GBSAVE_GAME_VERSION_5) +// utilGzRead(gzFile, pix, 256*224*sizeof(u16)); + } + + if (version < GBSAVE_GAME_VERSION_6) + { + utilGzRead(gzFile, gbPalette, 64 * sizeof(u16)); + } + else + utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); + + // todo: remove + utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); + + if (version < GBSAVE_GAME_VERSION_10) + { + if (!gbCgbMode && !gbSgbMode) + { + for (int i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; + } + } + + utilGzRead(gzFile, &gbMemory[0x8000], 0x8000); + + if (gbRamSize && gbRam) + { + utilGzRead(gzFile, gbRam, gbRamSize); + } + + gbMemoryMap[0x00] = &gbRom[0x0000]; + gbMemoryMap[0x01] = &gbRom[0x1000]; + gbMemoryMap[0x02] = &gbRom[0x2000]; + gbMemoryMap[0x03] = &gbRom[0x3000]; + gbMemoryMap[0x04] = &gbRom[0x4000]; + gbMemoryMap[0x05] = &gbRom[0x5000]; + gbMemoryMap[0x06] = &gbRom[0x6000]; + gbMemoryMap[0x07] = &gbRom[0x7000]; + gbMemoryMap[0x08] = &gbMemory[0x8000]; + gbMemoryMap[0x09] = &gbMemory[0x9000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbMemory[0xd000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + + type = gbRom[0x147]; + + switch (type) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + // MBC 1 + memoryUpdateMapMBC1(); + break; + case 0x05: + case 0x06: + // MBC2 + memoryUpdateMapMBC2(); + break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + // MBC 3 + memoryUpdateMapMBC3(); + break; + case 0x19: + case 0x1a: + case 0x1b: + // MBC5 + memoryUpdateMapMBC5(); + break; + case 0x1c: + case 0x1d: + case 0x1e: + // MBC 5 Rumble + memoryUpdateMapMBC5(); + break; + case 0x22: + // MBC 7 + memoryUpdateMapMBC7(); + break; + case 0xfe: + // HuC3 + memoryUpdateMapHuC3(); + break; + case 0xff: + // HuC1 + memoryUpdateMapHuC1(); + break; + } + + if (gbCgbMode) + { + if (!gbVram) + gbVram = (u8 *)malloc(0x4000 + 4); + if (!gbWram) + gbWram = (u8 *)malloc(0x8000 + 4); + utilGzRead(gzFile, gbVram, 0x4000); + utilGzRead(gzFile, gbWram, 0x8000); + + int value = register_SVBK; + if (value == 0) + value = 1; + + gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000]; + gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000]; + gbMemoryMap[0x0d] = &gbWram[value * 0x1000]; + } + else + { + if (gbVram) + { + free(gbVram); + gbVram = NULL; + } + if (gbWram) + { + free(gbWram); + gbWram = NULL; + } + } + + gbSoundReadGame(version, gzFile); + +#if 0 + if (gbBorderOn) + { + gbSgbRenderBorder(); + } + + systemRefreshScreen(); +#endif + + if (version > GBSAVE_GAME_VERSION_1) + gbCheatsReadGame(gzFile, version); + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + if (version >= GBSAVE_GAME_VERSION_11) // new to re-recording version: + { + extern int32 sensorX, sensorY; // from SDL.cpp + utilGzRead(gzFile, &sensorX, sizeof(sensorX)); + utilGzRead(gzFile, &sensorY, sizeof(sensorY)); + utilGzRead(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get carried + // back on loading a snapshot! + + bool8 movieSnapshot; + utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot)); + if (VBAMovieActive() && !movieSnapshot) + { + systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active.")); + goto failedLoadGB; + } + + if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added + // later on in the save format + { + uint32 movieInputDataSize = 0; + utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize)); + uint8 *local_movie_data = new uint8 [movieInputDataSize]; + int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize); + if (readBytes != movieInputDataSize) + { + systemMessage(0, N_("Corrupt movie snapshot.")); + if (local_movie_data) + delete [] local_movie_data; + goto failedLoadGB; + } + int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize); + if (local_movie_data) + delete [] local_movie_data; + if (code != MOVIE_SUCCESS && VBAMovieActive()) + { + char errStr [1024]; + strcpy(errStr, "Failed to load movie snapshot"); + switch (code) + { + case MOVIE_NOT_FROM_THIS_MOVIE: + strcat(errStr, ";\nSnapshot not from this movie"); break; + case MOVIE_NOT_FROM_A_MOVIE: + strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here... + case MOVIE_SNAPSHOT_INCONSISTENT: + strcat(errStr, ";\nSnapshot inconsistent with movie"); break; + case MOVIE_WRONG_FORMAT: + strcat(errStr, ";\nWrong format"); break; + } + strcat(errStr, "."); + systemMessage(0, N_(errStr)); + goto failedLoadGB; + } + } + utilGzRead(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); + } + + if (version >= GBSAVE_GAME_VERSION_13) // new to rerecording 19.4 wip (svn r22+): + { + utilGzRead(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); + utilGzRead(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); + utilGzRead(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); + } + + if (backupSafe) + { + remove(tempBackupName); + tempFailCount = 0; + } + + for (int i = 0; i < 4; ++i) + systemSetJoypad(i, gbJoymask[i] & 0xFFFF); + + // FIXME: horrible kludge + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); + + VBAUpdateButtonPressDisplay(); + VBAUpdateFrameCountDisplay(); + systemRefreshScreen(); + return true; + +failedLoadGB: + if (backupSafe) + { + tempFailCount++; + if (tempFailCount < 3) // fail no more than 2 times in a row + gbReadSaveState(tempBackupName); + remove(tempBackupName); + } + return false; +} + +bool gbReadMemSaveState(char *memory, int available) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "r"); + + backupSafe = false; + bool res = gbReadSaveStateFromStream(gzFile); + backupSafe = true; + + utilGzClose(gzFile); + + return res; +} + +bool gbReadSaveState(const char *name) +{ + gzFile gzFile = utilGzOpen(name, "rb"); + + if (gzFile == NULL) + { + return false; + } + + bool res = gbReadSaveStateFromStream(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool gbWritePNGFile(const char *fileName) +{ + if (gbBorderOn) + return utilWritePNGFile(fileName, 256, 224, pix); + return utilWritePNGFile(fileName, 160, 144, pix); +} + +bool gbWriteBMPFile(const char *fileName) +{ + if (gbBorderOn) + return utilWriteBMPFile(fileName, 256, 224, pix); + return utilWriteBMPFile(fileName, 160, 144, pix); +} + +void gbCleanUp() +{ + newFrame = true; + + GBSystemCounters.frameCount = 0; + GBSystemCounters.lagCount = 0; + GBSystemCounters.extraCount = 0; + GBSystemCounters.lagged = true; + GBSystemCounters.laggedLast = true; + + if (gbRam != NULL) + { + free(gbRam); + gbRam = NULL; + } + + if (gbRom != NULL) + { + free(gbRom); + gbRom = NULL; + } + + if (gbMemory != NULL) + { + free(gbMemory); + gbMemory = NULL; + } + + if (gbLineBuffer != NULL) + { + free(gbLineBuffer); + gbLineBuffer = NULL; + } + + if (origPix != NULL) + { + free(origPix); + origPix = NULL; + } + pix = NULL; + + gbSgbShutdown(); + + if (gbVram != NULL) + { + free(gbVram); + gbVram = NULL; + } + + if (gbWram != NULL) + { + free(gbWram); + gbWram = NULL; + } + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + memset(gbJoymask, 0, sizeof(gbJoymask)); + // FIXME: horrible kludge + memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); + + systemClearJoypads(); + systemResetSensor(); + +// gbLastTime = gbFrameCount = 0; + systemRefreshScreen(); +} + +bool gbLoadRom(const char *szFile) +{ + int size = 0; + + if (gbRom != NULL) + { + gbCleanUp(); + } + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + gbRom = utilLoad(szFile, + utilIsGBImage, + NULL, + size); + if (!gbRom) + return false; + + gbRomSize = size; + + return gbUpdateSizes(); +} + +bool gbUpdateSizes() +{ + if (gbRom[0x148] > 8) + { + systemMessage(MSG_UNSUPPORTED_ROM_SIZE, + N_("Unsupported rom size %02x"), gbRom[0x148]); + return false; + } + + if (gbRomSize < gbRomSizes[gbRom[0x148]]) + { + gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); + } + gbRomSize = gbRomSizes[gbRom[0x148]]; + gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; + + if (gbRom[0x149] > 5) + { + systemMessage(MSG_UNSUPPORTED_RAM_SIZE, + N_("Unsupported ram size %02x"), gbRom[0x149]); + return false; + } + + gbRamSize = gbRamSizes[gbRom[0x149]]; + gbRamSizeMask = gbRamSizesMasks[gbRom[0x149]]; + + if (gbRamSize) + { + gbRam = (u8 *)malloc(gbRamSize + 4); + memset(gbRam, 0xFF, gbRamSize + 4); + } + + int type = gbRom[0x147]; + + mapperReadRAM = NULL; + + switch (type) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + // MBC 1 + mapper = mapperMBC1ROM; + mapperRAM = mapperMBC1RAM; + break; + case 0x05: + case 0x06: + // MBC2 + mapper = mapperMBC2ROM; + mapperRAM = mapperMBC2RAM; + gbRamSize = 0x200; + gbRamSizeMask = 0x1ff; + break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + // MBC 3 + mapper = mapperMBC3ROM; + mapperRAM = mapperMBC3RAM; + mapperReadRAM = mapperMBC3ReadRAM; + break; + case 0x19: + case 0x1a: + case 0x1b: + // MBC5 + mapper = mapperMBC5ROM; + mapperRAM = mapperMBC5RAM; + break; + case 0x1c: + case 0x1d: + case 0x1e: + // MBC 5 Rumble + mapper = mapperMBC5ROM; + mapperRAM = mapperMBC5RAM; + break; + case 0x22: + // MBC 7 + mapper = mapperMBC7ROM; + mapperRAM = mapperMBC7RAM; + mapperReadRAM = mapperMBC7ReadRAM; + break; + case 0xfe: + // HuC3 + mapper = mapperHuC3ROM; + mapperRAM = mapperHuC3RAM; + mapperReadRAM = mapperHuC3ReadRAM; + break; + case 0xff: + // HuC1 + mapper = mapperHuC1ROM; + mapperRAM = mapperHuC1RAM; + break; + default: + systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE, + N_("Unknown cartridge type %02x"), type); + return false; + } + + switch (type) + { + case 0x03: + case 0x06: + case 0x0f: + case 0x10: + case 0x13: + case 0x1b: + case 0x1d: + case 0x1e: + case 0x22: + case 0xff: + gbBattery = 1; + break; + } + + gbInit(); + gbReset(); + + return true; +} + +void gbEmulate(int ticksToStop) +{ + gbRegister tempRegister; + u8 tempValue; + s8 offset; + + int clockTicks = 0; + gbDmaTicks = 0; + + register int opcode = 0; + + u32 newmask = 0; + if (newFrame) + { + extern void VBAOnExitingFrameBoundary(); + VBAOnExitingFrameBoundary(); + + // update joystick information + systemReadJoypads(); + + bool sensor = (gbRom[0x147] == 0x22); + + // read joystick + if (gbSgbMode && gbSgbMultiplayer) + { + if (gbSgbFourPlayers) + { + gbJoymask[0] = systemGetJoypad(0, sensor); + gbJoymask[1] = systemGetJoypad(1, false); + gbJoymask[2] = systemGetJoypad(2, false); + gbJoymask[3] = systemGetJoypad(3, false); + } + else + { + gbJoymask[0] = systemGetJoypad(0, sensor); + gbJoymask[1] = systemGetJoypad(1, false); + } + } + else + { + gbJoymask[0] = systemGetJoypad(0, sensor); + } + + // FIXME: horrible kludge + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); + +// if (sensor) +// systemUpdateMotionSensor(0); + + newmask = gbJoymask[0]; + if (newmask & 0xFF) + { + gbInterrupt |= 16; + } + + extButtons = (newmask >> 18); + speedup = (extButtons & 1) != 0; + + VBAMovieResetIfRequested(); + + CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); + + newFrame = false; + } + + for (;; ) + { +#ifndef FINAL_VERSION + if (systemDebug) + { + if (!(IFF & 0x80)) + { + if (systemDebug > 1) + { + sprintf(gbBuffer, "PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n", + PC.W, AF.W, BC.W, DE.W, HL.W, SP.W, IFF); + } + else + { + sprintf(gbBuffer, "PC=%04x I=%02x\n", PC.W, IFF); + } + log(gbBuffer); + } + } +#endif + if (IFF & 0x80) + { + if (register_LCDC & 0x80) + { + clockTicks = gbLcdTicks; + } + else + clockTicks = 100; + + if (gbLcdMode == 1 && (gbLcdLYIncrementTicks < clockTicks)) + clockTicks = gbLcdLYIncrementTicks; + + if (gbSerialOn && (gbSerialTicks < clockTicks)) + clockTicks = gbSerialTicks; + + if (gbTimerOn && (gbTimerTicks < clockTicks)) + clockTicks = gbTimerTicks; + + if (soundTicks && (soundTicks < clockTicks)) + clockTicks = soundTicks; + } + else + { + opcode = gbReadOpcode(PC.W); + CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); + PC.W++; + + if (IFF & 0x100) + { + IFF &= 0xff; + PC.W--; + } + + clockTicks = gbCycles[opcode]; + + switch (opcode) + { + case 0xCB: + // extended opcode + //CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); // is this desired? + opcode = gbReadOpcode(PC.W++); + clockTicks = gbCyclesCB[opcode]; + switch (opcode) + { +#include "gbCodesCB.h" + } + break; +#include "gbCodes.h" + } + } + + if (!emulating) + return; + + if (gbDmaTicks) + { + clockTicks += gbDmaTicks; + gbDmaTicks = 0; + } + + if (gbSgbMode) + { + if (gbSgbPacketTimeout) + { + gbSgbPacketTimeout -= clockTicks; + + if (gbSgbPacketTimeout <= 0) + gbSgbResetPacketState(); + } + } + + ticksToStop -= clockTicks; + + // DIV register emulation + gbDivTicks -= clockTicks; + while (gbDivTicks <= 0) + { + register_DIV++; + gbDivTicks += GBDIV_CLOCK_TICKS; + } + + if (register_LCDC & 0x80) + { + // LCD stuff + gbLcdTicks -= clockTicks; + if (gbLcdMode == 1) + { + // during V-BLANK,we need to increment LY at the same rate! + gbLcdLYIncrementTicks -= clockTicks; + while (gbLcdLYIncrementTicks <= 0) + { + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; + + if (register_LY < 153) + { + register_LY++; + + gbCompareLYToLYC(); + + if (register_LY >= 153) + gbLcdLYIncrementTicks = 6; + } + else + { + register_LY = 0x00; + // reset the window line + gbWindowLine = -1; + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS * 2; + gbCompareLYToLYC(); + } + } + } + + // our counter is off, see what we need to do + while (gbLcdTicks <= 0) + { + int framesToSkip = systemFramesToSkip(); + + switch (gbLcdMode) + { + case 0: + // H-Blank + register_LY++; + + gbCompareLYToLYC(); + + // check if we reached the V-Blank period + if (register_LY == 144) + { + // Yes, V-Blank + // set the LY increment counter + gbLcdLYIncrementTicks = gbLcdTicks + GBLY_INCREMENT_CLOCK_TICKS; + gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; + gbLcdMode = 1; + if (register_LCDC & 0x80) + { + gbInterrupt |= 1; // V-Blank interrupt + gbInterruptWait = 6; + if (register_STAT & 0x10) + gbInterrupt |= 2; + } + + systemFrame(); + + ++gbFrameCount; + u32 currentTime = systemGetClock(); + if (currentTime - gbLastTime >= 1000) + { + systemShowSpeed(int(float(gbFrameCount) * 100000 / (float(currentTime - gbLastTime) * 60) + .5f)); + gbLastTime = currentTime; + gbFrameCount = 0; + } + + ++GBSystemCounters.frameCount; + if (GBSystemCounters.lagged) + { + ++GBSystemCounters.lagCount; + } + GBSystemCounters.laggedLast = GBSystemCounters.lagged; + GBSystemCounters.lagged = true; + + extern void VBAOnEnteringFrameBoundary(); + VBAOnEnteringFrameBoundary(); + + newFrame = true; + + pauseAfterFrameAdvance = systemPauseOnFrame(); + + if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) + { + if (gbBorderOn) + gbSgbRenderBorder(); // clear unnecessary things on border (e.g. in-game text message) + + systemRenderFrame(); + gbFrameSkipCount = 0; + + bool capturePressed = (extButtons & 2) != 0; + if (capturePressed && !capturePrevious) + { + captureNumber = systemScreenCapture(captureNumber); + } + capturePrevious = capturePressed && !pauseAfterFrameAdvance; + } + else + { + ++gbFrameSkipCount; + } + + if (pauseAfterFrameAdvance) + { + systemSetPause(true); + } + } + else + { + // go the the OAM being accessed mode + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdMode = 2; + + // only one LCD interrupt per line. may need to generalize... + if (!(register_STAT & 0x40) || + (register_LY != register_LYC)) + { + if ((register_STAT & 0x28) == 0x20) + gbInterrupt |= 2; + } + } + + break; + case 1: + // V-Blank + // next mode is OAM being accessed mode + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdMode = 2; + if (!(register_STAT & 0x40) || + (register_LY != register_LYC)) + { + if ((register_STAT & 0x28) == 0x20) + gbInterrupt |= 2; + } + break; + case 2: + // OAM being accessed mode + + // next mode is OAM and VRAM in use + gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS; + gbLcdMode = 3; + break; + case 3: + // OAM and VRAM in use + // next mode is H-Blank + if (register_LY < 144) + { + if (!gbSgbMask) + { + if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) + { + gbRenderLine(); + gbDrawSprites(); + + switch (systemColorDepth) + { + case 16: + + { + u16 *dest = (u16 *)pix + + (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1) + + gbBorderColumnSkip; + for (int x = 0; x < 160; ) + { + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + } + if (gbBorderOn) + dest += gbBorderColumnSkip; + *dest++ = 0; // for filters that read one pixel more + break; + } + case 24: + + { + u8 *dest = (u8 *)pix + + 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + + gbBorderColumnSkip); + for (int x = 0; x < 160; ) + { + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + } + break; + } + case 32: + + { + u32 *dest = (u32 *)pix + + (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1) + + gbBorderColumnSkip; + for (int x = 0; x < 160; ) + { + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + } + break; + } + } + } + } + } + gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS; + gbLcdMode = 0; + // only one LCD interrupt per line. may need to generalize... + if (!(register_STAT & 0x40) || + (register_LY != register_LYC)) + { + if (register_STAT & 0x08) + gbInterrupt |= 2; + } + if (gbHdmaOn) + { + gbDoHdma(); + } + break; + } + // mark the correct lcd mode on STAT register + register_STAT = (register_STAT & 0xfc) | gbLcdMode; + } + } + + // serial emulation + if (gbSerialOn) + { +#ifdef LINK_EMULATION + if (linkConnected) + { + gbSerialTicks -= clockTicks; + + while (gbSerialTicks <= 0) + { + // increment number of shifted bits + gbSerialBits++; + linkProc(); + if (gbSerialOn && (gbMemory[0xff02] & 1)) + { + if (gbSerialBits == 8) + { + gbSerialBits = 0; + gbMemory[0xff01] = 0xff; + gbMemory[0xff02] &= 0x7f; + gbSerialOn = 0; + gbInterrupt |= 8; + gbSerialTicks = 0; + } + } + gbSerialTicks += GBSERIAL_CLOCK_TICKS; + } + } + else + { +#endif + if (gbMemory[0xff02] & 1) + { + gbSerialTicks -= clockTicks; + + // overflow + while (gbSerialTicks <= 0) + { + // shift serial byte to right and put a 1 bit in its place + // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1); + // increment number of shifted bits + gbSerialBits++; + if (gbSerialBits == 8) + { + // end of transmission + if (gbSerialFunction) // external device + gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); + else + gbMemory[0xff01] = 0xff; + gbSerialTicks = 0; + gbMemory[0xff02] &= 0x7f; + gbSerialOn = 0; + gbInterrupt |= 8; + gbSerialBits = 0; + } + else + gbSerialTicks += GBSERIAL_CLOCK_TICKS; + } + } +#ifdef LINK_EMULATION + } +#endif + } + + // timer emulation + if (gbTimerOn) + { + gbTimerTicks -= clockTicks; + + while (gbTimerTicks <= 0) + { + register_TIMA++; + + if (register_TIMA == 0) + { + // timer overflow! + + // reload timer modulo + register_TIMA = register_TMA; + + // flag interrupt + gbInterrupt |= 4; + } + + gbTimerTicks += gbTimerClockTicks; + } + } + + /* + if(soundOffFlag) + { + if(synchronize && !speedup) + { + synchronizeTicks -= clockTicks; + + while(synchronizeTicks < 0) + { + synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS; + + DWORD now = timeGetTime(); + gbElapsedTime += (now - timeNow); + + if(gbElapsedTime < 50) + { + DWORD diff = 50 - gbElapsedTime; + Sleep(diff); + timeNow = timeGetTime(); + elapsedTime = timeNow - now - diff; + if((int)elapsedTime < 0) + elapsedTime = 0; + } else + { + timeNow = timeGetTime(); + elapsedTime = 0; + } + } + } + } + */ + + soundTicks -= clockTicks; + while (soundTicks < 0) // must be < 1 when soundtick_t is real data type + { + soundTicks += SOUND_CLOCK_TICKS; + + gbSoundTick(); + } + + register_IF = gbInterrupt; + + if (IFF & 0x20) + { + IFF &= 0xdf; + IFF |= 0x01; + gbInterruptWait = 0; + } + else if (gbInterrupt) + { + if (gbInterruptWait == 0) + { + // gbInterruptWait = 0; + + if (IFF & 0x01) + { + if ((gbInterrupt & 1) && (register_IE & 1)) + { + gbVblank_interrupt(); + continue; + } + + if ((gbInterrupt & 2) && (register_IE & 2)) + { + gbLcd_interrupt(); + continue; + } + + if ((gbInterrupt & 4) && (register_IE & 4)) + { + gbTimer_interrupt(); + continue; + } + + if ((gbInterrupt & 8) && (register_IE & 8)) + { + gbSerial_interrupt(); + continue; + } + + if ((gbInterrupt & 16) && (register_IE & 16)) + { + gbJoypad_interrupt(); + continue; + } + } + } + else + { + gbInterruptWait -= clockTicks; + if (gbInterruptWait < 0) + gbInterruptWait = 0; + } + } + + if (useOldFrameTiming) + { + // old timing code + if (ticksToStop > 0) + continue; + } + else + { + if (!newFrame && (register_LCDC & 0x80) != 0) + continue; + } + + if (!(register_LCDC & 0x80)) + { + if (!useOldFrameTiming) + { + // FIXME: since register_LY can be reset to 0 by some games, frame length is variable + // and infinite loops can occurr + // for now, it IS necessary to do something on this condition or games like + // Megaman would freeze upon low-level restart interrupt sequence (Start+Select+A+B). + // the only sensible way to fix this issue is to implement the RIGHT frame timing +#ifdef WANTS_INCOMPLETE_WORKAROUND + if (systemReadJoypads()) + { + if (gbSgbMode && gbSgbMultiplayer) + { + if (gbSgbFourPlayers) + { + gbJoymask[0] = systemGetJoypad(0, false); + gbJoymask[1] = systemGetJoypad(1, false); + gbJoymask[2] = systemGetJoypad(2, false); + gbJoymask[3] = systemGetJoypad(3, false); + } + else + { + gbJoymask[0] = systemGetJoypad(0, false); + gbJoymask[1] = systemGetJoypad(1, false); + } + } + else + { + gbJoymask[0] = systemGetJoypad(0, false); + } + } + else + gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; +#else +#endif + } + } + + // makes sure frames are really divided across input sampling boundaries which occur at a constant rate + if (newFrame || useOldFrameTiming) + { +/// extern void VBAOnEnteringFrameBoundary(); +/// VBAOnEnteringFrameBoundary(); + + break; + } + } +} + +struct EmulatedSystem GBSystem = +{ + // emuMain + gbEmulate, + // emuReset + gbReset, + // emuCleanUp + gbCleanUp, + // emuReadBattery + gbReadBatteryFile, + // emuWriteBattery + gbWriteBatteryFile, + // emuReadBatteryFromStream + gbReadBatteryFromStream, + // emuWriteBatteryToStream + gbWriteBatteryToStream, + // emuReadState + gbReadSaveState, + // emuWriteState + gbWriteSaveState, + // emuReadStateFromStream + gbReadSaveStateFromStream, + // emuWriteStateToStream + gbWriteSaveStateToStream, + // emuReadMemState + gbReadMemSaveState, + // emuWriteMemState + gbWriteMemSaveState, + // emuWritePNG + gbWritePNGFile, + // emuWriteBMP + gbWriteBMPFile, + // emuUpdateCPSR + NULL, + // emuHasDebugger + false, + // emuCount +#ifdef FINAL_VERSION + 70000 / 4, +#else + 1000, +#endif +}; + +// is there a reason to use more than one set of counters? +EmulatedSystemCounters &GBSystemCounters = systemCounters; + +/* + EmulatedSystemCounters GBSystemCounters = + { + // frameCount + 0, + // lagCount + 0, + // lagged + true, + // laggedLast + true, + }; + */ diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/GB.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/GB.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,50 @@ +#ifndef VBA_GB_H +#define VBA_GB_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "zlib.h" +#include "../Port.h" + +typedef union +{ + struct + { +#ifdef WORDS_BIGENDIAN + u8 B1, B0; +#else + u8 B0, B1; +#endif + } B; + u16 W; +} gbRegister; + +extern bool gbLoadRom(const char *); +extern void gbEmulate(int); +extern bool gbIsGameboyRom(const char *); +extern void gbSoundReset(); +extern void gbSoundSetQuality(int); +extern void gbReset(bool userReset = false); +extern void gbCleanUp(); +extern bool gbWriteBatteryFile(const char *); +extern bool gbWriteBatteryFile(const char *, bool); +extern bool gbWriteBatteryToStream(gzFile); +extern bool gbReadBatteryFile(const char *); +extern bool gbReadBatteryFromStream(gzFile); +extern bool gbWriteSaveState(const char *); +extern bool gbWriteMemSaveState(char *, int); +extern bool gbReadSaveState(const char *); +extern bool gbReadMemSaveState(char *, int); +extern bool gbReadSaveStateFromStream(gzFile); +extern bool gbWriteSaveStateToStream(gzFile); +extern void gbSgbRenderBorder(); +extern bool gbWritePNGFile(const char *); +extern bool gbWriteBMPFile(const char *); +extern bool gbReadGSASnapshot(const char *); + +extern struct EmulatedSystem GBSystem; +extern struct EmulatedSystemCounters &GBSystemCounters; + +#endif // VBA_GB_H diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/Makefile.am Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,21 @@ +noinst_LIBRARIES = libgb.a + +libgb_a_SOURCES = \ + gbCheats.cpp \ + gbCheats.h \ + gbCodesCB.h \ + gbCodes.h \ + GB.cpp \ + GB.h \ + gbDis.cpp \ + gbGfx.cpp \ + gbGlobals.cpp \ + gbGlobals.h \ + gbMemory.cpp \ + gbMemory.h \ + gbPrinter.cpp \ + gbPrinter.h \ + gbSGB.cpp \ + gbSGB.h \ + gbSound.cpp \ + gbSound.h diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbCheats.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbCheats.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,477 @@ +#include +#include +#include +#include + +#include "../NLS.h" +#include "../common/System.h" +#include "../common/Util.h" + +#include "gbCheats.h" +#include "gbGlobals.h" + +gbCheat gbCheatList[100]; +int gbCheatNumber = 0; +bool gbCheatMap[0x10000]; + +extern bool8 cheatsEnabled; + +#define GBCHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9')) +#define GBCHEAT_HEX_VALUE(a) ((a) >= 'A' ? (a) - 'A' + 10 : (a) - '0') + +void gbCheatUpdateMap() +{ + memset(gbCheatMap, 0, 0x10000); + + for (int i = 0; i < gbCheatNumber; i++) + { + if (gbCheatList[i].enabled) + gbCheatMap[gbCheatList[i].address] = true; + } +} + +void gbCheatsSaveGame(gzFile gzFile) +{ + utilWriteInt(gzFile, gbCheatNumber); + if (gbCheatNumber) + utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); +} + +void gbCheatsReadGame(gzFile gzFile, int version) +{ + if (version <= 8) + { + int gbGgOn = utilReadInt(gzFile); + + if (gbGgOn) + { + int n = utilReadInt(gzFile); + gbXxCheat tmpCheat; + for (int i = 0; i < n; i++) + { + utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat)); + gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc); + } + } + + int gbGsOn = utilReadInt(gzFile); + + if (gbGsOn) + { + int n = utilReadInt(gzFile); + gbXxCheat tmpCheat; + for (int i = 0; i < n; i++) + { + utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat)); + gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc); + } + } + } + else + { + gbCheatNumber = utilReadInt(gzFile); + + if (gbCheatNumber) + { + utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); + } + } + + gbCheatUpdateMap(); +} + +void gbCheatsSaveCheatList(const char *file) +{ + if (gbCheatNumber == 0) + return; + FILE *f = fopen(file, "wb"); + if (f == NULL) + return; + int version = 1; + fwrite(&version, 1, sizeof(version), f); + int type = 1; + fwrite(&type, 1, sizeof(type), f); + fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f); + fwrite(gbCheatList, 1, sizeof(gbCheatList), f); + fclose(f); +} + +bool gbCheatsLoadCheatList(const char *file) +{ + gbCheatNumber = 0; + + gbCheatUpdateMap(); + + int count = 0; + + FILE *f = fopen(file, "rb"); + + if (f == NULL) + return false; + + int version = 0; + + if (fread(&version, 1, sizeof(version), f) != sizeof(version)) + { + fclose(f); + return false; + } + + if (version != 1) + { + systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION, + N_("Unsupported cheat list version %d"), version); + fclose(f); + return false; + } + + int type = 0; + if (fread(&type, 1, sizeof(type), f) != sizeof(type)) + { + fclose(f); + return false; + } + + if (type != 1) + { + systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE, + N_("Unsupported cheat list type %d"), type); + fclose(f); + return false; + } + + if (fread(&count, 1, sizeof(count), f) != sizeof(count)) + { + fclose(f); + return false; + } + + if (fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList)) + { + fclose(f); + return false; + } + + fclose(f); + gbCheatNumber = count; + gbCheatUpdateMap(); + + return true; +} + +bool gbVerifyGsCode(const char *code) +{ + int len = strlen(code); + + if (len == 0) + return true; + + if (len != 8) + return false; + + for (int i = 0; i < 8; i++) + if (!GBCHEAT_IS_HEX(code[i])) + return false; + + int address = GBCHEAT_HEX_VALUE(code[6]) << 12 | + GBCHEAT_HEX_VALUE(code[7]) << 8 | + GBCHEAT_HEX_VALUE(code[4]) << 4 | + GBCHEAT_HEX_VALUE(code[5]); + + if (address < 0xa000 || + address > 0xdfff) + return false; + + return true; +} + +void gbAddGsCheat(const char *code, const char *desc) +{ + if (gbCheatNumber > 99) + { + systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, + N_("Maximum number of cheats reached.")); + return; + } + + if (!gbVerifyGsCode(code)) + { + systemMessage(MSG_INVALID_GAMESHARK_CODE, + N_("Invalid GameShark code: %s"), code); + return; + } + + int i = gbCheatNumber; + + strcpy(gbCheatList[i].cheatCode, code); + strcpy(gbCheatList[i].cheatDesc, desc); + + gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 | + GBCHEAT_HEX_VALUE(code[1]); + + gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 | + GBCHEAT_HEX_VALUE(code[3]); + + gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 | + GBCHEAT_HEX_VALUE(code[7]) << 8 | + GBCHEAT_HEX_VALUE(code[4]) << 4 | + GBCHEAT_HEX_VALUE(code[5]); + + gbCheatList[i].compare = 0; + + gbCheatList[i].enabled = true; + + gbCheatMap[gbCheatList[i].address] = true; + + gbCheatNumber++; +} + +bool gbVerifyGgCode(const char *code) +{ + int len = strlen(code); + + if (len != 11 && + len != 7 && + len != 6 && + len != 0) + return false; + + if (len == 0) + return true; + + if (!GBCHEAT_IS_HEX(code[0])) + return false; + if (!GBCHEAT_IS_HEX(code[1])) + return false; + if (!GBCHEAT_IS_HEX(code[2])) + return false; + if (code[3] != '-') + return false; + if (!GBCHEAT_IS_HEX(code[4])) + return false; + if (!GBCHEAT_IS_HEX(code[5])) + return false; + if (!GBCHEAT_IS_HEX(code[6])) + return false; + if (code[7] != 0) + { + if (code[7] != '-') + return false; + if (code[8] != 0) + { + if (!GBCHEAT_IS_HEX(code[8])) + return false; + if (!GBCHEAT_IS_HEX(code[9])) + return false; + if (!GBCHEAT_IS_HEX(code[10])) + return false; + } + } + + // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) + + // GBCHEAT_HEX_VALUE(code[1]); + + int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) + + (GBCHEAT_HEX_VALUE(code[4]) << 4) + + (GBCHEAT_HEX_VALUE(code[5])) + + ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12); + + if (address >= 0x8000 && address <= 0x9fff) + return false; + + if (address >= 0xc000) + return false; + + if (code[7] == 0 || code[8] == '0') + return true; + + int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) + + (GBCHEAT_HEX_VALUE(code[10])); + compare = compare ^ 0xff; + compare = (compare >> 2) | ((compare << 6) & 0xc0); + compare ^= 0x45; + + int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9])); + + if (cloak >= 1 && cloak <= 7) + return false; + + return true; +} + +void gbAddGgCheat(const char *code, const char *desc) +{ + if (gbCheatNumber > 99) + { + systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, + N_("Maximum number of cheats reached.")); + return; + } + + if (!gbVerifyGgCode(code)) + { + systemMessage(MSG_INVALID_GAMEGENIE_CODE, + N_("Invalid GameGenie code: %s"), code); + return; + } + + int i = gbCheatNumber; + + int len = strlen(code); + + strcpy(gbCheatList[i].cheatCode, code); + strcpy(gbCheatList[i].cheatDesc, desc); + + gbCheatList[i].code = 1; + gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) + + GBCHEAT_HEX_VALUE(code[1]); + + gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) + + (GBCHEAT_HEX_VALUE(code[4]) << 4) + + (GBCHEAT_HEX_VALUE(code[5])) + + ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12); + + gbCheatList[i].compare = 0; + + if (len != 7 && len != 8) + { + int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) + + (GBCHEAT_HEX_VALUE(code[10])); + compare = compare ^ 0xff; + compare = (compare >> 2) | ((compare << 6) & 0xc0); + compare ^= 0x45; + + gbCheatList[i].compare = compare; + gbCheatList[i].code = 0; + } + + gbCheatList[i].enabled = true; + + gbCheatMap[gbCheatList[i].address] = true; + + gbCheatNumber++; +} + +void gbCheatRemove(int i) +{ + if (i < 0 || i >= gbCheatNumber) + { + systemMessage(MSG_INVALID_CHEAT_TO_REMOVE, + N_("Invalid cheat to remove %d"), i); + return; + } + + if ((i+1) < gbCheatNumber) + { + memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)* + (gbCheatNumber-i-1)); + } + + gbCheatNumber--; + + gbCheatUpdateMap(); +} + +void gbCheatRemoveAll() +{ + gbCheatNumber = 0; + gbCheatUpdateMap(); +} + +void gbCheatEnable(int i) +{ + if (i >= 0 && i < gbCheatNumber) + { + if (!gbCheatList[i].enabled) + { + gbCheatList[i].enabled = true; + gbCheatUpdateMap(); + } + } +} + +void gbCheatDisable(int i) +{ + if (i >= 0 && i < gbCheatNumber) + { + if (gbCheatList[i].enabled) + { + gbCheatList[i].enabled = false; + gbCheatUpdateMap(); + } + } +} + +bool gbCheatReadGSCodeFile(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if (!file) + return false; + + fseek(file, 0x18, SEEK_SET); + int count = 0; + fread(&count, 1, 2, file); + int dummy = 0; + gbCheatRemoveAll(); + char desc[13]; + char code[9]; + int i; + for (i = 0; i < count; i++) + { + fread(&dummy, 1, 2, file); + fread(desc, 1, 12, file); + desc[12] = 0; + fread(code, 1, 8, file); + code[8] = 0; + gbAddGsCheat(code, desc); + } + + for (i = 0; i < gbCheatNumber; i++) + gbCheatDisable(i); + + fclose(file); + return true; +} + +u8 gbCheatRead(u16 address) +{ + if (!cheatsEnabled) + return gbReadMemoryQuick(address); + + for (int i = 0; i < gbCheatNumber; i++) + { + if (gbCheatList[i].enabled && gbCheatList[i].address == address) + { + switch (gbCheatList[i].code) + { + case 0x100: // GameGenie support + if (gbReadMemoryQuick(address) == gbCheatList[i].compare) + return gbCheatList[i].value; + break; + case 0x00: + case 0x01: + case 0x80: + return gbCheatList[i].value; + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + if (address >= 0xd000 && address < 0xe000) + { + if (((gbMemoryMap[0x0d] - gbWram)/0x1000) == + (gbCheatList[i].code - 0x90)) + return gbCheatList[i].value; + } + else + return gbCheatList[i].value; + } + } + } + return gbReadMemoryQuick(address); +} + diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbCheats.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbCheats.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,44 @@ +#ifndef VBA_GB_CHEATS_H +#define VBA_GB_CHEATS_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +struct gbXxCheat +{ + char cheatDesc[100]; + char cheatCode[20]; +}; + +struct gbCheat +{ + char cheatCode[20]; + char cheatDesc[32]; + u16 address; + int code; + u8 compare; + u8 value; + bool enabled; +}; + +extern void gbCheatsSaveGame(gzFile); +extern void gbCheatsReadGame(gzFile, int); +extern void gbCheatsSaveCheatList(const char *); +extern bool gbCheatsLoadCheatList(const char *); +extern bool gbCheatReadGSCodeFile(const char *); + +extern void gbAddGsCheat(const char *, const char *); +extern void gbAddGgCheat(const char *, const char *); +extern void gbCheatRemove(int); +extern void gbCheatRemoveAll(); +extern void gbCheatEnable(int); +extern void gbCheatDisable(int); +extern u8 gbCheatRead(u16); + +extern int gbCheatNumber; +extern gbCheat gbCheatList[100]; +extern bool gbCheatMap[0x10000]; + +#endif // VBA_GB_CHEATS_H + diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbCodes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbCodes.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,1388 @@ + case 0x00: + // NOP + break; + case 0x01: + // LD BC, NNNN + BC.B.B0=gbReadMemory(PC.W++); + BC.B.B1=gbReadMemory(PC.W++); + break; + case 0x02: + // LD (BC),A + gbWriteMemory(BC.W,AF.B.B1); + break; + case 0x03: + // INC BC + BC.W++; + break; + case 0x04: + // INC B + BC.B.B1++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B1]| (BC.B.B1&0x0F? 0:H_FLAG); + break; + case 0x05: + // DEC B + BC.B.B1--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B1]| + ((BC.B.B1&0x0F)==0x0F? H_FLAG:0); + break; + case 0x06: + // LD B, NN + BC.B.B1=gbReadOpcode(PC.W++); + break; + case 0x07: + // RLCA + tempValue=AF.B.B1&0x80? C_FLAG:0; + AF.B.B1=((AF.B.B1<<1)|(AF.B.B1>>7)) & 0xFF; + AF.B.B0=tempValue; + break; + case 0x08: + // LD (NNNN), SP + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(tempRegister.W++,SP.B.B0); + gbWriteMemory(tempRegister.W,SP.B.B1); + break; + case 0x09: + // ADD HL,BC + tempRegister.W=(HL.W+BC.W)&0xFFFF; + AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^BC.W^tempRegister.W)&0x1000? H_FLAG:0)| + (((long)HL.W+(long)BC.W)&0x10000? C_FLAG:0); + HL.W=tempRegister.W; + break; + case 0x0a: + // LD A,(BC) + AF.B.B1=gbReadMemory(BC.W); + break; + case 0x0b: + // DEC BC + BC.W--; + break; + case 0x0c: + // INC C + BC.B.B0++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B0]| (BC.B.B0&0x0F? 0:H_FLAG); + break; + case 0x0d: + // DEC C + BC.B.B0--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[BC.B.B0]| + ((BC.B.B0&0x0F)==0x0F? H_FLAG:0); + break; + case 0x0e: + // LD C, NN + BC.B.B0=gbReadOpcode(PC.W++); + break; + case 0x0f: + // RRCA + tempValue=AF.B.B1&0x01; + AF.B.B1=(AF.B.B1>>1)|(tempValue? 0x80:0); + AF.B.B0=(tempValue<<4); + break; + case 0x10: + // STOP + opcode = gbReadOpcode(PC.W++); + if(gbCgbMode) { + if(gbReadMemoryQuick(0xff4d) & 1) { + gbSpeedSwitch(); + + if(gbSpeed == 0) + gbWriteMemoryQuick(0xff4d, 0x00); + else + gbWriteMemoryQuick(0xff4d, 0x80); + } + } + break; + case 0x11: + // LD DE, NNNN + DE.B.B0=gbReadMemory(PC.W++); + DE.B.B1=gbReadMemory(PC.W++); + break; + case 0x12: + // LD (DE),A + gbWriteMemory(DE.W,AF.B.B1); + break; + case 0x13: + // INC DE + DE.W++; + break; + case 0x14: + // INC D + DE.B.B1++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B1]| (DE.B.B1&0x0F? 0:H_FLAG); + break; + case 0x15: + // DEC D + DE.B.B1--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B1]| + ((DE.B.B1&0x0F)==0x0F? H_FLAG:0); + break; + case 0x16: + // LD D,NN + DE.B.B1=gbReadOpcode(PC.W++); + break; + case 0x17: + // RLA + tempValue=AF.B.B1&0x80? C_FLAG:0; + AF.B.B1=((AF.B.B1<<1)|((AF.B.B0&C_FLAG)>>4)) & 0xFF; + AF.B.B0=tempValue; + break; + case 0x18: + // JR NN + PC.W+=(s8)gbReadMemory(PC.W)+1; + break; + case 0x19: + // ADD HL,DE + tempRegister.W=(HL.W+DE.W)&0xFFFF; + AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^DE.W^tempRegister.W)&0x1000? H_FLAG:0)| + (((long)HL.W+(long)DE.W)&0x10000? C_FLAG:0); + HL.W=tempRegister.W; + break; + case 0x1a: + // LD A,(DE) + AF.B.B1=gbReadMemory(DE.W); + break; + case 0x1b: + // DEC DE + DE.W--; + break; + case 0x1c: + // INC E + DE.B.B0++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B0]| (DE.B.B0&0x0F? 0:H_FLAG); + break; + case 0x1d: + // DEC E + DE.B.B0--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[DE.B.B0]| + ((DE.B.B0&0x0F)==0x0F? H_FLAG:0); + break; + case 0x1e: + // LD E,NN + DE.B.B0=gbReadOpcode(PC.W++); + break; + case 0x1f: + // RRA + tempValue=AF.B.B1&0x01; + AF.B.B1=(AF.B.B1>>1)|(AF.B.B0&C_FLAG? 0x80:0); + AF.B.B0=(tempValue<<4); + break; + case 0x20: + // JR NZ,NN + if(AF.B.B0&Z_FLAG) + PC.W++; + else { + PC.W+=(s8)gbReadMemory(PC.W)+1; + clockTicks++; + } + break; + case 0x21: + // LD HL,NNNN + HL.B.B0=gbReadMemory(PC.W++); + HL.B.B1=gbReadMemory(PC.W++); + break; + case 0x22: + // LDI (HL),A + gbWriteMemory(HL.W++,AF.B.B1); + break; + case 0x23: + // INC HL + HL.W++; + break; + case 0x24: + // INC H + HL.B.B1++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B1]| (HL.B.B1&0x0F? 0:H_FLAG); + break; + case 0x25: + // DEC H + HL.B.B1--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B1]| + ((HL.B.B1&0x0F)==0x0F? H_FLAG:0); + break; + case 0x26: + // LD H,NN + HL.B.B1=gbReadOpcode(PC.W++); + break; + case 0x27: + // DAA + tempRegister.W=AF.B.B1; + if(AF.B.B0&C_FLAG) tempRegister.W|=256; + if(AF.B.B0&H_FLAG) tempRegister.W|=512; + if(AF.B.B0&N_FLAG) tempRegister.W|=1024; + AF.W=DAATable[tempRegister.W]; + break; + case 0x28: + // JR Z,NN + if(AF.B.B0&Z_FLAG) { + PC.W+=(s8)gbReadMemory(PC.W)+1; + clockTicks++; + } else + PC.W++; + break; + case 0x29: + // ADD HL,HL + tempRegister.W=(HL.W+HL.W)&0xFFFF; AF.B.B0= (AF.B.B0 & Z_FLAG)| + ((HL.W^HL.W^tempRegister.W)&0x1000? H_FLAG:0)| + (((long)HL.W+(long)HL.W)&0x10000? C_FLAG:0); + HL.W=tempRegister.W; + break; + case 0x2a: + // LDI A,(HL) + AF.B.B1 = gbReadMemory(HL.W++); + break; + case 0x2b: + // DEC HL + HL.W--; + break; + case 0x2c: + // INC L + HL.B.B0++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B0]| (HL.B.B0&0x0F? 0:H_FLAG); + break; + case 0x2d: + // DEC L + HL.B.B0--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[HL.B.B0]| + ((HL.B.B0&0x0F)==0x0F? H_FLAG:0); + break; + case 0x2e: + // LD L,NN + HL.B.B0=gbReadOpcode(PC.W++); + break; + case 0x2f: + // CPL + AF.B.B1 ^= 255; + AF.B.B0|=N_FLAG|H_FLAG; + break; + case 0x30: + // JR NC,NN + if(AF.B.B0&C_FLAG) + PC.W++; + else { + PC.W+=(s8)gbReadMemory(PC.W)+1; + clockTicks++; + } + break; + case 0x31: + // LD SP,NNNN + SP.B.B0=gbReadMemory(PC.W++); + SP.B.B1=gbReadMemory(PC.W++); + break; + case 0x32: + // LDD (HL),A + gbWriteMemory(HL.W--,AF.B.B1); + break; + case 0x33: + // INC SP + SP.W++; + break; + case 0x34: + // INC (HL) + tempValue=(gbReadMemory(HL.W)+1) & 0xFF; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[tempValue]| (tempValue&0x0F? 0:H_FLAG); + gbWriteMemory(HL.W,tempValue); + break; + case 0x35: + // DEC (HL) + tempValue=(gbReadMemory(HL.W)-1) & 0xFF; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[tempValue]| + ((tempValue&0x0F)==0x0F? H_FLAG:0);gbWriteMemory(HL.W,tempValue); + break; + case 0x36: + // LD (HL),NN + gbWriteMemory(HL.W,gbReadOpcode(PC.W++)); + break; + case 0x37: + // SCF + AF.B.B0 = AF.B.B0 & Z_FLAG | C_FLAG; + break; +case 0x38: + // JR C,NN + if(AF.B.B0&C_FLAG) { + PC.W+=(s8)gbReadMemory(PC.W)+1; + clockTicks ++; + } else + PC.W++; + break; + case 0x39: + // ADD HL,SP + tempRegister.W=(HL.W+SP.W)&0xFFFF; + AF.B.B0= (AF.B.B0 & Z_FLAG)| ((HL.W^SP.W^tempRegister.W)&0x1000? H_FLAG:0)| + (((long)HL.W+(long)SP.W)&0x10000? C_FLAG:0); + HL.W=tempRegister.W; + break; + case 0x3a: + // LDD A,(HL) + AF.B.B1 = gbReadMemory(HL.W--); + break; + case 0x3b: + // DEC SP + SP.W--; + break; + case 0x3c: + // INC A + AF.B.B1++; + AF.B.B0= (AF.B.B0 & C_FLAG)|ZeroTable[AF.B.B1]| (AF.B.B1&0x0F? 0:H_FLAG); + break; + case 0x3d: + // DEC A + AF.B.B1--; + AF.B.B0= N_FLAG|(AF.B.B0 & C_FLAG)|ZeroTable[AF.B.B1]| + ((AF.B.B1&0x0F)==0x0F? H_FLAG:0); + break; + case 0x3e: + // LD A,NN + AF.B.B1=gbReadOpcode(PC.W++); + break; + case 0x3f: + // CCF + AF.B.B0^=C_FLAG;AF.B.B0&=~(N_FLAG|H_FLAG); + break; + case 0x40: + // LD B,B + BC.B.B1=BC.B.B1; + break; + case 0x41: + // LD B,C + BC.B.B1=BC.B.B0; + break; + case 0x42: + // LD B,D + BC.B.B1=DE.B.B1; + break; + case 0x43: + // LD B,E + BC.B.B1=DE.B.B0; + break; + case 0x44: + // LD B,H + BC.B.B1=HL.B.B1; + break; + case 0x45: + // LD B,L + BC.B.B1=HL.B.B0; + break; + case 0x46: + // LD B,(HL) + BC.B.B1=gbReadMemory(HL.W); + break; + case 0x47: + // LD B,A + BC.B.B1=AF.B.B1; + break; + case 0x48: + // LD C,B + BC.B.B0=BC.B.B1; + break; + case 0x49: + // LD C,C + BC.B.B0=BC.B.B0; + break; + case 0x4a: + // LD C,D + BC.B.B0=DE.B.B1; + break; + case 0x4b: + // LD C,E + BC.B.B0=DE.B.B0; + break; + case 0x4c: + // LD C,H + BC.B.B0=HL.B.B1; + break; + case 0x4d: + // LD C,L + BC.B.B0=HL.B.B0; + break; + case 0x4e: + // LD C,(HL) + BC.B.B0=gbReadMemory(HL.W); + break; + case 0x4f: + // LD C,A + BC.B.B0=AF.B.B1; + break; + case 0x50: + // LD D,B + DE.B.B1=BC.B.B1; + break; + case 0x51: + // LD D,C + DE.B.B1=BC.B.B0; + break; + case 0x52: + // LD D,D + DE.B.B1=DE.B.B1; + break; + case 0x53: + // LD D,E + DE.B.B1=DE.B.B0; + break; + case 0x54: + // LD D,H + DE.B.B1=HL.B.B1; + break; + case 0x55: + // LD D,L + DE.B.B1=HL.B.B0; + break; + case 0x56: + // LD D,(HL) + DE.B.B1=gbReadMemory(HL.W); + break; + case 0x57: + // LD D,A + DE.B.B1=AF.B.B1; + break; + case 0x58: + // LD E,B + DE.B.B0=BC.B.B1; + break; + case 0x59: + // LD E,C + DE.B.B0=BC.B.B0; + break; + case 0x5a: + // LD E,D + DE.B.B0=DE.B.B1; + break; + case 0x5b: + // LD E,E + DE.B.B0=DE.B.B0; + break; + case 0x5c: + // LD E,H + DE.B.B0=HL.B.B1; + break; + case 0x5d: + // LD E,L + DE.B.B0=HL.B.B0; + break; + case 0x5e: + // LD E,(HL) + DE.B.B0=gbReadMemory(HL.W); + break; + case 0x5f: + // LD E,A + DE.B.B0=AF.B.B1; + break; + case 0x60: + // LD H,B + HL.B.B1=BC.B.B1; + break; + case 0x61: + // LD H,C + HL.B.B1=BC.B.B0; + break; + case 0x62: + // LD H,D + HL.B.B1=DE.B.B1; + break; + case 0x63: + // LD H,E + HL.B.B1=DE.B.B0; + break; + case 0x64: + // LD H,H + HL.B.B1=HL.B.B1; + break; + case 0x65: + // LD H,L + HL.B.B1=HL.B.B0; + break; + case 0x66: + // LD H,(HL) + HL.B.B1=gbReadMemory(HL.W); + break; + case 0x67: + // LD H,A + HL.B.B1=AF.B.B1; + break; + case 0x68: + // LD L,B + HL.B.B0=BC.B.B1; + break; + case 0x69: + // LD L,C + HL.B.B0=BC.B.B0; + break; + case 0x6a: + // LD L,D + HL.B.B0=DE.B.B1; + break; + case 0x6b: + // LD L,E + HL.B.B0=DE.B.B0; + break; + case 0x6c: + // LD L,H + HL.B.B0=HL.B.B1; + break; + case 0x6d: + // LD L,L + HL.B.B0=HL.B.B0; + break; + case 0x6e: + // LD L,(HL) + HL.B.B0=gbReadMemory(HL.W); + break; + case 0x6f: + // LD L,A + HL.B.B0=AF.B.B1; + break; + case 0x70: + // LD (HL),B + gbWriteMemory(HL.W,BC.B.B1); + break; + case 0x71: + // LD (HL),C + gbWriteMemory(HL.W,BC.B.B0); + break; + case 0x72: + // LD (HL),D + gbWriteMemory(HL.W,DE.B.B1); + break; + case 0x73: + // LD (HL),E + gbWriteMemory(HL.W,DE.B.B0); + break; + case 0x74: + // LD (HL),H + gbWriteMemory(HL.W,HL.B.B1); + break; + case 0x75: + // LD (HL),L + gbWriteMemory(HL.W,HL.B.B0); + break; + case 0x76: + // HALT + if(IFF & 1) { + PC.W--; + IFF |= 0x80; + } else { + if((register_IE & register_IF) > 0) + IFF |= 0x100; + else { + PC.W--; + IFF |= 0x81; + } + } + break; + case 0x77: + // LD (HL),A + gbWriteMemory(HL.W,AF.B.B1); + break; + case 0x78: + // LD A,B + AF.B.B1=BC.B.B1; + break; + case 0x79: + // LD A,C + AF.B.B1=BC.B.B0; + break; + case 0x7a: + // LD A,D + AF.B.B1=DE.B.B1; + break; + case 0x7b: + // LD A,E + AF.B.B1=DE.B.B0; + break; + case 0x7c: + // LD A,H + AF.B.B1=HL.B.B1; + break; + case 0x7d: + // LD A,L + AF.B.B1=HL.B.B0; + break; + case 0x7e: + // LD A,(HL) + AF.B.B1=gbReadMemory(HL.W); + break; + case 0x7f: + // LD A,A + AF.B.B1=AF.B.B1; + break; + case 0x80: + // ADD B + tempRegister.W=AF.B.B1+BC.B.B1; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x81: + // ADD C + tempRegister.W=AF.B.B1+BC.B.B0; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x82: + // ADD D + tempRegister.W=AF.B.B1+DE.B.B1; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x83: + // ADD E + tempRegister.W=AF.B.B1+DE.B.B0; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x84: + // ADD H + tempRegister.W=AF.B.B1+HL.B.B1; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x85: + // ADD L + tempRegister.W=AF.B.B1+HL.B.B0; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x86: + // ADD (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1+tempValue; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x87: + // ADD A + tempRegister.W=AF.B.B1+AF.B.B1; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x88: + // ADC B: + tempRegister.W=AF.B.B1+BC.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x89: + // ADC C + tempRegister.W=AF.B.B1+BC.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8a: + // ADC D + tempRegister.W=AF.B.B1+DE.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8b: + // ADC E + tempRegister.W=AF.B.B1+DE.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8c: + // ADC H + tempRegister.W=AF.B.B1+HL.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); AF.B.B1=tempRegister.B.B0; + break; + case 0x8d: + // ADC L + tempRegister.W=AF.B.B1+HL.B.B0+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8e: + // ADC (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1+tempValue+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x8f: + // ADC A + tempRegister.W=AF.B.B1+AF.B.B1+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x90: + // SUB B + tempRegister.W=AF.B.B1-BC.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x91: + // SUB C + tempRegister.W=AF.B.B1-BC.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x92: + // SUB D + tempRegister.W=AF.B.B1-DE.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x93: + // SUB E + tempRegister.W=AF.B.B1-DE.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x94: + // SUB H + tempRegister.W=AF.B.B1-HL.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x95: + // SUB L + tempRegister.W=AF.B.B1-HL.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x96: + // SUB (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1-tempValue; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x97: + // SUB A + AF.B.B1=0; + AF.B.B0=N_FLAG|Z_FLAG; + break; + case 0x98: + // SBC B + tempRegister.W=AF.B.B1-BC.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x99: + // SBC C + tempRegister.W=AF.B.B1-BC.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9a: + // SBC D + tempRegister.W=AF.B.B1-DE.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9b: + // SBC E + tempRegister.W=AF.B.B1-DE.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9c: + // SBC H + tempRegister.W=AF.B.B1-HL.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9d: + // SBC L + tempRegister.W=AF.B.B1-HL.B.B0-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9e: + // SBC (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1-tempValue-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0x9f: + // SBC A + tempRegister.W=AF.B.B1-AF.B.B1-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^AF.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xa0: + // AND B + AF.B.B1&=BC.B.B1; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa1: + // AND C + AF.B.B1&=BC.B.B0; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa2: + // AND_D + AF.B.B1&=DE.B.B1; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa3: + // AND E + AF.B.B1&=DE.B.B0; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa4: + // AND H + AF.B.B1&=HL.B.B1; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa5: + // AND L + AF.B.B1&=HL.B.B0; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa6: + // AND (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B1&=tempValue; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa7: + // AND A + AF.B.B1&=AF.B.B1; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xa8: + // XOR B + AF.B.B1^=BC.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xa9: + // XOR C + AF.B.B1^=BC.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xaa: + // XOR D + AF.B.B1^=DE.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xab: + // XOR E + AF.B.B1^=DE.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xac: + // XOR H + AF.B.B1^=HL.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xad: + // XOR L + AF.B.B1^=HL.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xae: + // XOR (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B1^=tempValue; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xaf: + // XOR A + AF.B.B1=0; + AF.B.B0=Z_FLAG; + break; + case 0xb0: + // OR B + AF.B.B1|=BC.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb1: + // OR C + AF.B.B1|=BC.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb2: + // OR D + AF.B.B1|=DE.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb3: + // OR E + AF.B.B1|=DE.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb4: + // OR H + AF.B.B1|=HL.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb5: + // OR L + AF.B.B1|=HL.B.B0; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb6: + // OR (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B1|=tempValue; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb7: + // OR A + AF.B.B1|=AF.B.B1; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xb8: + // CP B: + tempRegister.W=AF.B.B1-BC.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xb9: + // CP C + tempRegister.W=AF.B.B1-BC.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^BC.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xba: + // CP D + tempRegister.W=AF.B.B1-DE.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbb: + // CP E + tempRegister.W=AF.B.B1-DE.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^DE.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbc: + // CP H + tempRegister.W=AF.B.B1-HL.B.B1; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B1^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbd: + // CP L + tempRegister.W=AF.B.B1-HL.B.B0; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^HL.B.B0^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbe: + // CP (HL) + tempValue=gbReadMemory(HL.W); + tempRegister.W=AF.B.B1-tempValue; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xbf: + // CP A + AF.B.B0=N_FLAG|Z_FLAG; + break; + case 0xc0: + // RET NZ + if(!(AF.B.B0&Z_FLAG)) { + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + clockTicks += 3; + } + break; + case 0xc1: + // POP BC + BC.B.B0=gbReadMemory(SP.W++); + BC.B.B1=gbReadMemory(SP.W++); + break; + case 0xc2: + // JP NZ,NNNN + if(AF.B.B0&Z_FLAG) + PC.W+=2; + else { + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W); + PC.W=tempRegister.W; + clockTicks++; + } + break; + case 0xc3: + // JP NNNN + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W); + PC.W=tempRegister.W; + break; + case 0xc4: + // CALL NZ,NNNN + if(AF.B.B0&Z_FLAG) + PC.W+=2; + else { + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + clockTicks += 3; + } + break; + case 0xc5: + // PUSH BC + gbWriteMemory(--SP.W,BC.B.B1); + gbWriteMemory(--SP.W,BC.B.B0); + break; + case 0xc6: + // ADD NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1+tempValue; + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10 ? H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xc7: + // RST 00 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0000; + break; + case 0xc8: + // RET Z + if(AF.B.B0&Z_FLAG) { + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + clockTicks += 3; + } + break; + case 0xc9: + // RET + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + break; + case 0xca: + // JP Z,NNNN + if(AF.B.B0&Z_FLAG) { + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W); + PC.W=tempRegister.W; + clockTicks++; + } else + PC.W+=2; + break; + // CB done outside + case 0xcc: + // CALL Z,NNNN + if(AF.B.B0&Z_FLAG) { + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + clockTicks += 3; + } else + PC.W+=2; + break; + case 0xcd: + // CALL NNNN + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + break; + case 0xce: + // ADC NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1+tempValue+(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= (tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xcf: + // RST 08 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0008; + break; + case 0xd0: + // RET NC + if(!(AF.B.B0&C_FLAG)) { + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + clockTicks += 3; + } + break; + case 0xd1: + // POP DE + DE.B.B0=gbReadMemory(SP.W++); + DE.B.B1=gbReadMemory(SP.W++); + break; + case 0xd2: + // JP NC,NNNN + if(AF.B.B0&C_FLAG) + PC.W+=2; + else { + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W); + PC.W=tempRegister.W; + clockTicks++; + } + break; + // D3 illegal + case 0xd4: + // CALL NC,NNNN + if(AF.B.B0&C_FLAG) + PC.W+=2; + else { + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + clockTicks += 3; + } + break; + case 0xd5: + // PUSH DE + gbWriteMemory(--SP.W,DE.B.B1); + gbWriteMemory(--SP.W,DE.B.B0); + break; + case 0xd6: + // SUB NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1-tempValue; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xd7: + // RST 10 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0010; + break; + case 0xd8: + // RET C + if(AF.B.B0&C_FLAG) { + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + clockTicks += 4; + } + break; + case 0xd9: + // RETI + PC.B.B0=gbReadMemory(SP.W++); + PC.B.B1=gbReadMemory(SP.W++); + IFF |= 0x01; + break; + case 0xda: + // JP C,NNNN + if(AF.B.B0&C_FLAG) { + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W); + PC.W=tempRegister.W; + clockTicks++; + } else + PC.W+=2; + break; + // DB illegal + case 0xdc: + // CALL C,NNNN + if(AF.B.B0&C_FLAG) { + tempRegister.B.B0=gbReadMemory(PC.W++); + tempRegister.B.B1=gbReadMemory(PC.W++); + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=tempRegister.W; + clockTicks += 3; + } else + PC.W+=2; + break; + // DD illegal + case 0xde: + // SBC NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1-tempValue-(AF.B.B0&C_FLAG ? 1 : 0); + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + AF.B.B1=tempRegister.B.B0; + break; + case 0xdf: + // RST 18 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0018; + break; + case 0xe0: + // LD (FF00+NN),A + gbWriteMemory(0xff00 + gbReadOpcode(PC.W++),AF.B.B1); + break; + case 0xe1: + // POP HL + HL.B.B0=gbReadMemory(SP.W++); + HL.B.B1=gbReadMemory(SP.W++); + break; + case 0xe2: + // LD (FF00+C),A + gbWriteMemory(0xff00 + BC.B.B0,AF.B.B1); + break; + // E3 illegal + // E4 illegal + case 0xe5: + // PUSH HL + gbWriteMemory(--SP.W,HL.B.B1); + gbWriteMemory(--SP.W,HL.B.B0); + break; + case 0xe6: + // AND NN + tempValue=gbReadOpcode(PC.W++); + AF.B.B1&=tempValue; + AF.B.B0=H_FLAG|ZeroTable[AF.B.B1]; + break; + case 0xe7: + // RST 20 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0020; + break; + case 0xe8: + // ADD SP,NN + offset = (s8)gbReadOpcode(PC.W++); + + if(offset >= 0) { + tempRegister.W = SP.W + offset; + AF.B.B0 = (SP.W > tempRegister.W ? C_FLAG : 0) | + ((SP.W^offset^tempRegister.W)&0x1000? H_FLAG:0); + SP.W = tempRegister.W; + } else { + tempRegister.W = SP.W + offset; + AF.B.B0 = (SP.W < tempRegister.W ? C_FLAG : 0) | + ((SP.W^offset^tempRegister.W)&0x1000?H_FLAG:0); + SP.W = tempRegister.W; + } + break; + case 0xe9: + // LD PC,HL + PC.W=HL.W; + break; + case 0xea: + // LD (NNNN),A + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + gbWriteMemory(tempRegister.W,AF.B.B1); + break; + // EB illegal + // EC illegal + // ED illegal + case 0xee: + // XOR NN + tempValue=gbReadOpcode(PC.W++); + AF.B.B1^=tempValue; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xef: + // RST 28 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0028; + break; + case 0xf0: + // LD A,(FF00+NN) + AF.B.B1 = gbReadMemory(0xff00+gbReadOpcode(PC.W++)); + break; + case 0xf1: + // POP AF + AF.B.B0=gbReadMemory(SP.W++); + AF.B.B1=gbReadMemory(SP.W++); + break; + case 0xf2: + // LD A,(FF00+C) + AF.B.B1 = gbReadMemory(0xff00+BC.B.B0); + break; + case 0xf3: + // DI + // IFF&=0xFE; + IFF&=(~0x21); + break; + // F4 illegal + case 0xf5: + // PUSH AF + gbWriteMemory(--SP.W,AF.B.B1); + gbWriteMemory(--SP.W,AF.B.B0); + break; + case 0xf6: + // OR NN + tempValue=gbReadOpcode(PC.W++); + AF.B.B1|=tempValue; + AF.B.B0=ZeroTable[AF.B.B1]; + break; + case 0xf7: + // RST 30 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0030; + break; + case 0xf8: + // LD HL,SP+NN + offset = (s8)gbReadOpcode(PC.W++); + if(offset >= 0) { + tempRegister.W = SP.W + offset; + AF.B.B0 = (SP.W > tempRegister.W ? C_FLAG : 0) | + ((SP.W^offset^tempRegister.W)&0x1000? H_FLAG:0); + HL.W = tempRegister.W; + } else { + tempRegister.W = SP.W + offset; + AF.B.B0 = (SP.W < tempRegister.W ? C_FLAG : 0) | + ((SP.W^offset^tempRegister.W)&0x1000?H_FLAG:0); + HL.W = tempRegister.W; + } + break; + case 0xf9: + // LD SP,HL + SP.W=HL.W; + break; + case 0xfa: + // LD A,(NNNN) + tempRegister.B.B0=gbReadOpcode(PC.W++); + tempRegister.B.B1=gbReadOpcode(PC.W++); + AF.B.B1=gbReadMemory(tempRegister.W); + break; + case 0xfb: + // EI + IFF|=0x20; + break; + // FC illegal + // FD illegal + case 0xfe: + // CP NN + tempValue=gbReadOpcode(PC.W++); + tempRegister.W=AF.B.B1-tempValue; + AF.B.B0= N_FLAG|(tempRegister.B.B1?C_FLAG:0)|ZeroTable[tempRegister.B.B0]| + ((AF.B.B1^tempValue^tempRegister.B.B0)&0x10?H_FLAG:0); + break; + case 0xff: + // RST 38 + gbWriteMemory(--SP.W,PC.B.B1); + gbWriteMemory(--SP.W,PC.B.B0); + PC.W=0x0038; + break; + default: + systemMessage(0, N_("Unknown opcode %02x at %04x"), + gbReadOpcode(PC.W-1),PC.W-1); + emulating = false; + return; diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbCodesCB.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbCodesCB.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,1269 @@ + case 0x00: + // RLC B + AF.B.B0 = (BC.B.B1 & 0x80)?C_FLAG:0; + BC.B.B1 = ((BC.B.B1<<1) | (BC.B.B1>>7)) & 0xFF; + AF.B.B0 |= ZeroTable[BC.B.B1]; + break; + case 0x01: + // RLC C + AF.B.B0 = (BC.B.B0 & 0x80)?C_FLAG:0; + BC.B.B0 = ((BC.B.B0<<1) | (BC.B.B0>>7)) & 0xFF; + AF.B.B0 |= ZeroTable[BC.B.B0]; + break; + case 0x02: + // RLC D + AF.B.B0 = (DE.B.B1 & 0x80)?C_FLAG:0; + DE.B.B1 = ((DE.B.B1<<1) | (DE.B.B1>>7)) & 0xFF; + AF.B.B0 |= ZeroTable[DE.B.B1]; + break; + case 0x03: + // RLC E + AF.B.B0 = (DE.B.B0 & 0x80)?C_FLAG:0; + DE.B.B0 = ((DE.B.B0<<1) | (DE.B.B0>>7)) & 0xFF; + AF.B.B0 |= ZeroTable[DE.B.B0]; + break; + case 0x04: + // RLC H + AF.B.B0 = (HL.B.B1 & 0x80)?C_FLAG:0; + HL.B.B1 = ((HL.B.B1<<1) | (HL.B.B1>>7)) & 0xFF; + AF.B.B0 |= ZeroTable[HL.B.B1]; + break; + case 0x05: + // RLC L + AF.B.B0 = (HL.B.B0 & 0x80)?C_FLAG:0; + HL.B.B0 = ((HL.B.B0<<1) | (HL.B.B0>>7)) & 0xFF; + AF.B.B0 |= ZeroTable[HL.B.B0]; + break; + case 0x06: + // RLC (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0 = (tempValue & 0x80)?C_FLAG:0; + tempValue = ((tempValue<<1) | (tempValue>>7)) & 0xFF; + AF.B.B0 |= ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x07: + // RLC A + AF.B.B0 = (AF.B.B1 & 0x80)?C_FLAG:0; + AF.B.B1 = ((AF.B.B1<<1) | (AF.B.B1>>7)) & 0xFF; + AF.B.B0 |= ZeroTable[AF.B.B1]; + break; + case 0x08: + // RRC B + AF.B.B0=(BC.B.B1&0x01 ? C_FLAG : 0); + BC.B.B1=((BC.B.B1>>1)|(BC.B.B1<<7)) & 0xFF; + AF.B.B0|=ZeroTable[BC.B.B1]; + break; + case 0x09: + // RRC C + AF.B.B0=(BC.B.B0&0x01 ? C_FLAG : 0); + BC.B.B0=((BC.B.B0>>1)|(BC.B.B0<<7)) & 0xFF; + AF.B.B0|=ZeroTable[BC.B.B0]; + break; + case 0x0a: + // RRC D + AF.B.B0=(DE.B.B1&0x01 ? C_FLAG : 0); + DE.B.B1=((DE.B.B1>>1)|(DE.B.B1<<7)) & 0xFF; + AF.B.B0|=ZeroTable[DE.B.B1]; + break; + case 0x0b: + // RRC E + AF.B.B0=(DE.B.B0&0x01 ? C_FLAG : 0); + DE.B.B0=((DE.B.B0>>1)|(DE.B.B0<<7)) & 0xFF; + AF.B.B0|=ZeroTable[DE.B.B0]; + break; + case 0x0c: + // RRC H + AF.B.B0=(HL.B.B1&0x01 ? C_FLAG : 0); + HL.B.B1=((HL.B.B1>>1)|(HL.B.B1<<7)) & 0xFF; + AF.B.B0|=ZeroTable[HL.B.B1]; + break; + case 0x0d: + // RRC L + AF.B.B0=(HL.B.B0&0x01 ? C_FLAG : 0); + HL.B.B0=((HL.B.B0>>1)|(HL.B.B0<<7)) & 0xFF; + AF.B.B0|=ZeroTable[HL.B.B0]; + break; + case 0x0e: + // RRC (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(tempValue&0x01 ? C_FLAG : 0); + tempValue=((tempValue>>1)|(tempValue<<7)) & 0xFF; + AF.B.B0|=ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x0f: + // RRC A + AF.B.B0=(AF.B.B1&0x01 ? C_FLAG : 0); + AF.B.B1=((AF.B.B1>>1)|(AF.B.B1<<7)) & 0xFF; + AF.B.B0|=ZeroTable[AF.B.B1]; + break; + case 0x10: + // RL B + if(BC.B.B1&0x80) { + BC.B.B1=((BC.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[BC.B.B1]|C_FLAG; + } else { + BC.B.B1=((BC.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[BC.B.B1]; + } + break; + case 0x11: + // RL C + if(BC.B.B0&0x80) { + BC.B.B0=((BC.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[BC.B.B0]|C_FLAG; + } else { + BC.B.B0=((BC.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[BC.B.B0]; + } + break; + case 0x12: + // RL D + if(DE.B.B1&0x80) { + DE.B.B1=((DE.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[DE.B.B1]|C_FLAG; + } else { + DE.B.B1=((DE.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[DE.B.B1]; + } + break; + case 0x13: + // RL E + if(DE.B.B0&0x80) { + DE.B.B0=((DE.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[DE.B.B0]|C_FLAG; + } else { + DE.B.B0=((DE.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[DE.B.B0]; + } + break; + case 0x14: + // RL H + if(HL.B.B1&0x80) { + HL.B.B1=((HL.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[HL.B.B1]|C_FLAG; + } else { + HL.B.B1=((HL.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[HL.B.B1]; + } + break; + case 0x15: + // RL L + if(HL.B.B0&0x80) { + HL.B.B0=((HL.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[HL.B.B0]|C_FLAG; + } else { + HL.B.B0=((HL.B.B0<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[HL.B.B0]; + } + break; + case 0x16: + // RL (HL) + tempValue=gbReadMemory(HL.W); + if(tempValue&0x80) { + tempValue=((tempValue<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[tempValue]|C_FLAG; + } else { + tempValue=((tempValue<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[tempValue]; + } + gbWriteMemory(HL.W,tempValue); + break; + case 0x17: + // RL A + if(AF.B.B1&0x80) { + AF.B.B1=((AF.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[AF.B.B1]|C_FLAG; + } else { + AF.B.B1=((AF.B.B1<<1)|(AF.B.B0&C_FLAG ? 1 : 0)) & 0xFF; + AF.B.B0=ZeroTable[AF.B.B1]; + } + break; + case 0x18: + // RR B + if(BC.B.B1&0x01) { + BC.B.B1=(BC.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[BC.B.B1]|C_FLAG; + } else { + BC.B.B1=(BC.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[BC.B.B1]; + } + break; + case 0x19: + // RR C + if(BC.B.B0&0x01) { + BC.B.B0=(BC.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[BC.B.B0]|C_FLAG; + } else { + BC.B.B0=(BC.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[BC.B.B0]; + } + break; + case 0x1a: + // RR D + if(DE.B.B1&0x01) { + DE.B.B1=(DE.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[DE.B.B1]|C_FLAG; + } else { + DE.B.B1=(DE.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[DE.B.B1]; + } + break; + case 0x1b: + // RR E + if(DE.B.B0&0x01) { + DE.B.B0=(DE.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[DE.B.B0]|C_FLAG; + } else { + DE.B.B0=(DE.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[DE.B.B0]; + } + break; + case 0x1c: + // RR H + if(HL.B.B1&0x01) { + HL.B.B1=(HL.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[HL.B.B1]|C_FLAG; + } else { + HL.B.B1=(HL.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[HL.B.B1]; + } + break; + case 0x1d: + // RR L + if(HL.B.B0&0x01) { + HL.B.B0=(HL.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[HL.B.B0]|C_FLAG; + } else { + HL.B.B0=(HL.B.B0>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[HL.B.B0]; + } + break; + case 0x1e: + // RR (HL) + tempValue=gbReadMemory(HL.W); + if(tempValue&0x01) { + tempValue=(tempValue>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[tempValue]|C_FLAG; + } else { + tempValue=(tempValue>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[tempValue]; + } + gbWriteMemory(HL.W,tempValue); + break; + case 0x1f: + // RR A + if(AF.B.B1&0x01) { + AF.B.B1=(AF.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[AF.B.B1]|C_FLAG; + } else { + AF.B.B1=(AF.B.B1>>1)|(AF.B.B0 & C_FLAG ? 0x80:0); + AF.B.B0=ZeroTable[AF.B.B1]; + } + break; + case 0x20: + // SLA B + AF.B.B0=(BC.B.B1&0x80?C_FLAG : 0); + BC.B.B1<<=1; + AF.B.B0|=ZeroTable[BC.B.B1]; + break; + case 0x21: + // SLA C + AF.B.B0=(BC.B.B0&0x80?C_FLAG : 0); + BC.B.B0<<=1; + AF.B.B0|=ZeroTable[BC.B.B0]; + break; + case 0x22: + // SLA D + AF.B.B0=(DE.B.B1&0x80?C_FLAG : 0); + DE.B.B1<<=1; + AF.B.B0|=ZeroTable[DE.B.B1]; + break; + case 0x23: + // SLA E + AF.B.B0=(DE.B.B0&0x80?C_FLAG : 0); + DE.B.B0<<=1; + AF.B.B0|=ZeroTable[DE.B.B0]; + break; + case 0x24: + // SLA H + AF.B.B0=(HL.B.B1&0x80?C_FLAG : 0); + HL.B.B1<<=1; + AF.B.B0|=ZeroTable[HL.B.B1]; + break; + case 0x25: + // SLA L + AF.B.B0=(HL.B.B0&0x80?C_FLAG : 0); + HL.B.B0<<=1; + AF.B.B0|=ZeroTable[HL.B.B0]; + break; + case 0x26: + // SLA (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(tempValue&0x80?C_FLAG : 0); + tempValue<<=1; + AF.B.B0|=ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x27: + // SLA A + AF.B.B0=(AF.B.B1&0x80?C_FLAG : 0); + AF.B.B1<<=1; + AF.B.B0|=ZeroTable[AF.B.B1]; + break; + case 0x28: + // SRA B + AF.B.B0=(BC.B.B1&0x01 ? C_FLAG: 0); + BC.B.B1=(BC.B.B1>>1)|(BC.B.B1&0x80); + AF.B.B0|=ZeroTable[BC.B.B1]; + break; + case 0x29: + // SRA C + AF.B.B0=(BC.B.B0&0x01 ? C_FLAG: 0); + BC.B.B0=(BC.B.B0>>1)|(BC.B.B0&0x80); + AF.B.B0|=ZeroTable[BC.B.B0]; + break; + case 0x2a: + // SRA D + AF.B.B0=(DE.B.B1&0x01 ? C_FLAG: 0); + DE.B.B1=(DE.B.B1>>1)|(DE.B.B1&0x80); + AF.B.B0|=ZeroTable[DE.B.B1]; + break; + case 0x2b: + // SRA E + AF.B.B0=(DE.B.B0&0x01 ? C_FLAG: 0); + DE.B.B0=(DE.B.B0>>1)|(DE.B.B0&0x80); + AF.B.B0|=ZeroTable[DE.B.B0]; + break; + case 0x2c: + // SRA H + AF.B.B0=(HL.B.B1&0x01 ? C_FLAG: 0); + HL.B.B1=(HL.B.B1>>1)|(HL.B.B1&0x80); + AF.B.B0|=ZeroTable[HL.B.B1]; + break; + case 0x2d: + // SRA L + AF.B.B0=(HL.B.B0&0x01 ? C_FLAG: 0); + HL.B.B0=(HL.B.B0>>1)|(HL.B.B0&0x80); + AF.B.B0|=ZeroTable[HL.B.B0]; + break; + case 0x2e: + // SRA (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(tempValue&0x01 ? C_FLAG: 0); + tempValue=(tempValue>>1)|(tempValue&0x80); + AF.B.B0|=ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x2f: + // SRA A + AF.B.B0=(AF.B.B1&0x01 ? C_FLAG: 0); + AF.B.B1=(AF.B.B1>>1)|(AF.B.B1&0x80); + AF.B.B0|=ZeroTable[AF.B.B1]; + break; + case 0x30: + // SWAP B + BC.B.B1 = (BC.B.B1&0xf0)>>4 | (BC.B.B1&0x0f)<<4; + AF.B.B0 = ZeroTable[BC.B.B1]; + break; + case 0x31: + // SWAP C + BC.B.B0 = (BC.B.B0&0xf0)>>4 | (BC.B.B0&0x0f)<<4; + AF.B.B0 = ZeroTable[BC.B.B0]; + break; + case 0x32: + // SWAP D + DE.B.B1 = (DE.B.B1&0xf0)>>4 | (DE.B.B1&0x0f)<<4; + AF.B.B0 = ZeroTable[DE.B.B1]; + break; + case 0x33: + // SWAP E + DE.B.B0 = (DE.B.B0&0xf0)>>4 | (DE.B.B0&0x0f)<<4; + AF.B.B0 = ZeroTable[DE.B.B0]; + break; + case 0x34: + // SWAP H + HL.B.B1 = (HL.B.B1&0xf0)>>4 | (HL.B.B1&0x0f)<<4; + AF.B.B0 = ZeroTable[HL.B.B1]; + break; + case 0x35: + // SWAP L + HL.B.B0 = (HL.B.B0&0xf0)>>4 | (HL.B.B0&0x0f)<<4; + AF.B.B0 = ZeroTable[HL.B.B0]; + break; + case 0x36: + // SWAP (HL) + tempValue=gbReadMemory(HL.W); + tempValue = (tempValue&0xf0)>>4 | (tempValue&0x0f)<<4; + AF.B.B0 = ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x37: + // SWAP A + AF.B.B1 = (AF.B.B1&0xf0)>>4 | (AF.B.B1&0x0f)<<4; + AF.B.B0 = ZeroTable[AF.B.B1]; + break; + case 0x38: + // SRL B + AF.B.B0=(BC.B.B1&0x01)?C_FLAG:0; + BC.B.B1>>=1; + AF.B.B0|=ZeroTable[BC.B.B1]; + break; + case 0x39: + // SRL C + AF.B.B0=(BC.B.B0&0x01)?C_FLAG:0; + BC.B.B0>>=1; + AF.B.B0|=ZeroTable[BC.B.B0]; + break; + case 0x3a: + // SRL D + AF.B.B0=(DE.B.B1&0x01)?C_FLAG:0; + DE.B.B1>>=1; + AF.B.B0|=ZeroTable[DE.B.B1]; + break; + case 0x3b: + // SRL E + AF.B.B0=(DE.B.B0&0x01)?C_FLAG:0; + DE.B.B0>>=1; + AF.B.B0|=ZeroTable[DE.B.B0]; + break; + case 0x3c: + // SRL H + AF.B.B0=(HL.B.B1&0x01)?C_FLAG:0; + HL.B.B1>>=1; + AF.B.B0|=ZeroTable[HL.B.B1]; + break; + case 0x3d: + // SRL L + AF.B.B0=(HL.B.B0&0x01)?C_FLAG:0; + HL.B.B0>>=1; + AF.B.B0|=ZeroTable[HL.B.B0]; + break; + case 0x3e: + // SRL (HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(tempValue&0x01)?C_FLAG:0; + tempValue>>=1; + AF.B.B0|=ZeroTable[tempValue]; + gbWriteMemory(HL.W,tempValue); + break; + case 0x3f: + // SRL A + AF.B.B0=(AF.B.B1&0x01)?C_FLAG:0; + AF.B.B1>>=1; + AF.B.B0|=ZeroTable[AF.B.B1]; + break; + case 0x40: + // BIT 0,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<0)? 0:Z_FLAG); + break; + case 0x41: + // BIT 0,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<0)? 0:Z_FLAG); + break; + case 0x42: + // BIT 0,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<0)? 0:Z_FLAG); + break; + case 0x43: + // BIT 0,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<0)? 0:Z_FLAG); + break; + case 0x44: + // BIT 0,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<0)? 0:Z_FLAG); + break; + case 0x45: + // BIT 0,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<0)? 0:Z_FLAG); + break; + case 0x46: + // BIT 0,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<0)? 0:Z_FLAG); + break; + case 0x47: + // BIT 0,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<0)? 0:Z_FLAG); + break; + case 0x48: + // BIT 1,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<1)? 0:Z_FLAG); + break; + case 0x49: + // BIT 1,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<1)? 0:Z_FLAG); + break; + case 0x4a: + // BIT 1,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<1)? 0:Z_FLAG); + break; + case 0x4b: + // BIT 1,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<1)? 0:Z_FLAG); + break; + case 0x4c: + // BIT 1,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<1)? 0:Z_FLAG); + break; + case 0x4d: + // BIT 1,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<1)? 0:Z_FLAG); + break; + case 0x4e: + // BIT 1,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<1)? 0:Z_FLAG); + break; + case 0x4f: + // BIT 1,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<1)? 0:Z_FLAG); + break; + case 0x50: + // BIT 2,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<2)? 0:Z_FLAG); + break; + case 0x51: + // BIT 2,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<2)? 0:Z_FLAG); + break; + case 0x52: + // BIT 2,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<2)? 0:Z_FLAG); + break; + case 0x53: + // BIT 2,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<2)? 0:Z_FLAG); + break; + case 0x54: + // BIT 2,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<2)? 0:Z_FLAG); + break; + case 0x55: + // BIT 2,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<2)? 0:Z_FLAG); + break; + case 0x56: + // BIT 2,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<2)? 0:Z_FLAG); + break; + case 0x57: + // BIT 2,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<2)? 0:Z_FLAG); + break; + case 0x58: + // BIT 3,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<3)? 0:Z_FLAG); + break; + case 0x59: + // BIT 3,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<3)? 0:Z_FLAG); + break; + case 0x5a: + // BIT 3,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<3)? 0:Z_FLAG); + break; + case 0x5b: + // BIT 3,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<3)? 0:Z_FLAG); + break; + case 0x5c: + // BIT 3,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<3)? 0:Z_FLAG); + break; + case 0x5d: + // BIT 3,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<3)? 0:Z_FLAG); + break; + case 0x5e: + // BIT 3,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<3)? 0:Z_FLAG); + break; + case 0x5f: + // BIT 3,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<3)? 0:Z_FLAG); + break; + case 0x60: + // BIT 4,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<4)? 0:Z_FLAG); + break; + case 0x61: + // BIT 4,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<4)? 0:Z_FLAG); + break; + case 0x62: + // BIT 4,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<4)? 0:Z_FLAG); + break; + case 0x63: + // BIT 4,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<4)? 0:Z_FLAG); + break; + case 0x64: + // BIT 4,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<4)? 0:Z_FLAG); + break; + case 0x65: + // BIT 4,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<4)? 0:Z_FLAG); + break; + case 0x66: + // BIT 4,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<4)? 0:Z_FLAG); + break; + case 0x67: + // BIT 4,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<4)? 0:Z_FLAG); + break; + case 0x68: + // BIT 5,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<5)? 0:Z_FLAG); + break; + case 0x69: + // BIT 5,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<5)? 0:Z_FLAG); + break; + case 0x6a: + // BIT 5,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<5)? 0:Z_FLAG); + break; + case 0x6b: + // BIT 5,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<5)? 0:Z_FLAG); + break; + case 0x6c: + // BIT 5,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<5)? 0:Z_FLAG); + break; + case 0x6d: + // BIT 5,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<5)? 0:Z_FLAG); + break; + case 0x6e: + // BIT 5,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<5)? 0:Z_FLAG); + break; + case 0x6f: + // BIT 5,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<5)? 0:Z_FLAG); + break; + case 0x70: + // BIT 6,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<6)? 0:Z_FLAG); + break; + case 0x71: + // BIT 6,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<6)? 0:Z_FLAG); + break; + case 0x72: + // BIT 6,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<6)? 0:Z_FLAG); + break; + case 0x73: + // BIT 6,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<6)? 0:Z_FLAG); + break; + case 0x74: + // BIT 6,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<6)? 0:Z_FLAG); + break; + case 0x75: + // BIT 6,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<6)? 0:Z_FLAG); + break; + case 0x76: + // BIT 6,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<6)? 0:Z_FLAG); + break; + case 0x77: + // BIT 6,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<6)? 0:Z_FLAG); + break; + case 0x78: + // BIT 7,B + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B1&(1<<7)? 0:Z_FLAG); + break; + case 0x79: + // BIT 7,C + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(BC.B.B0&(1<<7)? 0:Z_FLAG); + break; + case 0x7a: + // BIT 7,D + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B1&(1<<7)? 0:Z_FLAG); + break; + case 0x7b: + // BIT 7,E + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(DE.B.B0&(1<<7)? 0:Z_FLAG); + break; + case 0x7c: + // BIT 7,H + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B1&(1<<7)? 0:Z_FLAG); + break; + case 0x7d: + // BIT 7,L + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(HL.B.B0&(1<<7)? 0:Z_FLAG); + break; + case 0x7e: + // BIT 7,(HL) + tempValue=gbReadMemory(HL.W); + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(tempValue&(1<<7)? 0:Z_FLAG); + break; + case 0x7f: + // BIT 7,A + AF.B.B0=(AF.B.B0&C_FLAG)|H_FLAG|(AF.B.B1&(1<<7)? 0:Z_FLAG); + break; + case 0x80: + // RES 0,B + BC.B.B1&=~(1<<0); + break; + case 0x81: + // RES 0,C + BC.B.B0&=~(1<<0); + break; + case 0x82: + // RES 0,D + DE.B.B1&=~(1<<0); + break; + case 0x83: + // RES 0,E + DE.B.B0&=~(1<<0); + break; + case 0x84: + // RES 0,H + HL.B.B1&=~(1<<0); + break; + case 0x85: + // RES 0,L + HL.B.B0&=~(1<<0); + break; + case 0x86: + // RES 0,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<0); + gbWriteMemory(HL.W,tempValue); + break; + case 0x87: + // RES 0,A + AF.B.B1&=~(1<<0); + break; + case 0x88: + // RES 1,B + BC.B.B1&=~(1<<1); + break; + case 0x89: + // RES 1,C + BC.B.B0&=~(1<<1); + break; + case 0x8a: + // RES 1,D + DE.B.B1&=~(1<<1); + break; + case 0x8b: + // RES 1,E + DE.B.B0&=~(1<<1); + break; + case 0x8c: + // RES 1,H + HL.B.B1&=~(1<<1); + break; + case 0x8d: + // RES 1,L + HL.B.B0&=~(1<<1); + break; + case 0x8e: + // RES 1,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<1); + gbWriteMemory(HL.W,tempValue); + break; + case 0x8f: + // RES 1,A + AF.B.B1&=~(1<<1); + break; + case 0x90: + // RES 2,B + BC.B.B1&=~(1<<2); + break; + case 0x91: + // RES 2,C + BC.B.B0&=~(1<<2); + break; + case 0x92: + // RES 2,D + DE.B.B1&=~(1<<2); + break; + case 0x93: + // RES 2,E + DE.B.B0&=~(1<<2); + break; + case 0x94: + // RES 2,H + HL.B.B1&=~(1<<2); + break; + case 0x95: + // RES 2,L + HL.B.B0&=~(1<<2); + break; + case 0x96: + // RES 2,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<2); + gbWriteMemory(HL.W,tempValue); + break; + case 0x97: + // RES 2,A + AF.B.B1&=~(1<<2); + break; + case 0x98: + // RES 3,B + BC.B.B1&=~(1<<3); + break; + case 0x99: + // RES 3,C + BC.B.B0&=~(1<<3); + break; + case 0x9a: + // RES 3,D + DE.B.B1&=~(1<<3); + break; + case 0x9b: + // RES 3,E + DE.B.B0&=~(1<<3); + break; + case 0x9c: + // RES 3,H + HL.B.B1&=~(1<<3); + break; + case 0x9d: + // RES 3,L + HL.B.B0&=~(1<<3); + break; + case 0x9e: + // RES 3,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<3); + gbWriteMemory(HL.W,tempValue); + break; + case 0x9f: + // RES 3,A + AF.B.B1&=~(1<<3); + break; + case 0xa0: + // RES 4,B + BC.B.B1&=~(1<<4); + break; + case 0xa1: + // RES 4,C + BC.B.B0&=~(1<<4); + break; + case 0xa2: + // RES 4,D + DE.B.B1&=~(1<<4); + break; + case 0xa3: + // RES 4,E + DE.B.B0&=~(1<<4); + break; + case 0xa4: + // RES 4,H + HL.B.B1&=~(1<<4); + break; + case 0xa5: + // RES 4,L + HL.B.B0&=~(1<<4); + break; + case 0xa6: + // RES 4,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<4); + gbWriteMemory(HL.W,tempValue); + break; + case 0xa7: + // RES 4,A + AF.B.B1&=~(1<<4); + break; + case 0xa8: + // RES 5,B + BC.B.B1&=~(1<<5); + break; + case 0xa9: + // RES 5,C + BC.B.B0&=~(1<<5); + break; + case 0xaa: + // RES 5,D + DE.B.B1&=~(1<<5); + break; + case 0xab: + // RES 5,E + DE.B.B0&=~(1<<5); + break; + case 0xac: + // RES 5,H + HL.B.B1&=~(1<<5); + break; + case 0xad: + // RES 5,L + HL.B.B0&=~(1<<5); + break; + case 0xae: + // RES 5,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<5); + gbWriteMemory(HL.W,tempValue); + break; + case 0xaf: + // RES 5,A + AF.B.B1&=~(1<<5); + break; + case 0xb0: + // RES 6,B + BC.B.B1&=~(1<<6); + break; + case 0xb1: + // RES 6,C + BC.B.B0&=~(1<<6); + break; + case 0xb2: + // RES 6,D + DE.B.B1&=~(1<<6); + break; + case 0xb3: + // RES 6,E + DE.B.B0&=~(1<<6); + break; + case 0xb4: + // RES 6,H + HL.B.B1&=~(1<<6); + break; + case 0xb5: + // RES 6,L + HL.B.B0&=~(1<<6); + break; + case 0xb6: + // RES 6,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<6); + gbWriteMemory(HL.W,tempValue); + break; + case 0xb7: + // RES 6,A + AF.B.B1&=~(1<<6); + break; + case 0xb8: + // RES 7,B + BC.B.B1&=~(1<<7); + break; + case 0xb9: + // RES 7,C + BC.B.B0&=~(1<<7); + break; + case 0xba: + // RES 7,D + DE.B.B1&=~(1<<7); + break; + case 0xbb: + // RES 7,E + DE.B.B0&=~(1<<7); + break; + case 0xbc: + // RES 7,H + HL.B.B1&=~(1<<7); + break; + case 0xbd: + // RES 7,L + HL.B.B0&=~(1<<7); + break; + case 0xbe: + // RES 7,(HL) + tempValue=gbReadMemory(HL.W); + tempValue&=~(1<<7); + gbWriteMemory(HL.W,tempValue); + break; + case 0xbf: + // RES 7,A + AF.B.B1&=~(1<<7); + break; + case 0xc0: + // SET 0,B + BC.B.B1|=1<<0; + break; + case 0xc1: + // SET 0,C + BC.B.B0|=1<<0; + break; + case 0xc2: + // SET 0,D + DE.B.B1|=1<<0; + break; + case 0xc3: + // SET 0,E + DE.B.B0|=1<<0; + break; + case 0xc4: + // SET 0,H + HL.B.B1|=1<<0; + break; + case 0xc5: + // SET 0,L + HL.B.B0|=1<<0; + break; + case 0xc6: + // SET 0,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<0; + gbWriteMemory(HL.W,tempValue); + break; + case 0xc7: + // SET 0,A + AF.B.B1|=1<<0; + break; + case 0xc8: + // SET 1,B + BC.B.B1|=1<<1; + break; + case 0xc9: + // SET 1,C + BC.B.B0|=1<<1; + break; + case 0xca: + // SET 1,D + DE.B.B1|=1<<1; + break; + case 0xcb: + // SET 1,E + DE.B.B0|=1<<1; + break; + case 0xcc: + // SET 1,H + HL.B.B1|=1<<1; + break; + case 0xcd: + // SET 1,L + HL.B.B0|=1<<1; + break; + case 0xce: + // SET 1,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<1; + gbWriteMemory(HL.W,tempValue); + break; + case 0xcf: + // SET 1,A + AF.B.B1|=1<<1; + break; + case 0xd0: + // SET 2,B + BC.B.B1|=1<<2; + break; + case 0xd1: + // SET 2,C + BC.B.B0|=1<<2; + break; + case 0xd2: + // SET 2,D + DE.B.B1|=1<<2; + break; + case 0xd3: + // SET 2,E + DE.B.B0|=1<<2; + break; + case 0xd4: + // SET 2,H + HL.B.B1|=1<<2; + break; + case 0xd5: + // SET 2,L + HL.B.B0|=1<<2; + break; + case 0xd6: + // SET 2,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<2; + gbWriteMemory(HL.W,tempValue); + break; + case 0xd7: + // SET 2,A + AF.B.B1|=1<<2; + break; + case 0xd8: + // SET 3,B + BC.B.B1|=1<<3; + break; + case 0xd9: + // SET 3,C + BC.B.B0|=1<<3; + break; + case 0xda: + // SET 3,D + DE.B.B1|=1<<3; + break; + case 0xdb: + // SET 3,E + DE.B.B0|=1<<3; + break; + case 0xdc: + // SET 3,H + HL.B.B1|=1<<3; + break; + case 0xdd: + // SET 3,L + HL.B.B0|=1<<3; + break; + case 0xde: + // SET 3,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<3; + gbWriteMemory(HL.W,tempValue); + break; + case 0xdf: + // SET 3,A + AF.B.B1|=1<<3; + break; + case 0xe0: + // SET 4,B + BC.B.B1|=1<<4; + break; + case 0xe1: + // SET 4,C + BC.B.B0|=1<<4; + break; + case 0xe2: + // SET 4,D + DE.B.B1|=1<<4; + break; + case 0xe3: + // SET 4,E + DE.B.B0|=1<<4; + break; + case 0xe4: + // SET 4,H + HL.B.B1|=1<<4; + break; + case 0xe5: + // SET 4,L + HL.B.B0|=1<<4; + break; + case 0xe6: + // SET 4,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<4; + gbWriteMemory(HL.W,tempValue); + break; + case 0xe7: + // SET 4,A + AF.B.B1|=1<<4; + break; + case 0xe8: + // SET 5,B + BC.B.B1|=1<<5; + break; + case 0xe9: + // SET 5,C + BC.B.B0|=1<<5; + break; + case 0xea: + // SET 5,D + DE.B.B1|=1<<5; + break; + case 0xeb: + // SET 5,E + DE.B.B0|=1<<5; + break; + case 0xec: + // SET 5,H + HL.B.B1|=1<<5; + break; + case 0xed: + // SET 5,L + HL.B.B0|=1<<5; + break; + case 0xee: + // SET 5,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<5; + gbWriteMemory(HL.W,tempValue); + break; + case 0xef: + // SET 5,A + AF.B.B1|=1<<5; + break; + case 0xf0: + // SET 6,B + BC.B.B1|=1<<6; + break; + case 0xf1: + // SET 6,C + BC.B.B0|=1<<6; + break; + case 0xf2: + // SET 6,D + DE.B.B1|=1<<6; + break; + case 0xf3: + // SET 6,E + DE.B.B0|=1<<6; + break; + case 0xf4: + // SET 6,H + HL.B.B1|=1<<6; + break; + case 0xf5: + // SET 6,L + HL.B.B0|=1<<6; + break; + case 0xf6: + // SET 6,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<6; + gbWriteMemory(HL.W,tempValue); + break; + case 0xf7: + // SET 6,A + AF.B.B1|=1<<6; + break; + case 0xf8: + // SET 7,B + BC.B.B1|=1<<7; + break; + case 0xf9: + // SET 7,C + BC.B.B0|=1<<7; + break; + case 0xfa: + // SET 7,D + DE.B.B1|=1<<7; + break; + case 0xfb: + // SET 7,E + DE.B.B0|=1<<7; + break; + case 0xfc: + // SET 7,H + HL.B.B1|=1<<7; + break; + case 0xfd: + // SET 7,L + HL.B.B0|=1<<7; + break; + case 0xfe: + // SET 7,(HL) + tempValue=gbReadMemory(HL.W); + tempValue|=1<<7; + gbWriteMemory(HL.W,tempValue); + break; + case 0xff: + // SET 7,A + AF.B.B1|=1<<7; + break; + default: + systemMessage(0, N_("Unknown opcode %02x at %04x"), + gbReadOpcode(PC.W-1),PC.W-1); + emulating = false; + return; diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbDis.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbDis.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,239 @@ +#include +#include + +#include "gbGlobals.h" + +typedef struct +{ + u8 mask; + u8 value; + char *mnen; +} GBOPCODE; + +static char *registers[] = +{ "B", "C", "D", "E", "H", "L", "(HL)", "A" }; + +static char *registers16[] = +{ "BC", "DE", "HL", "SP", // for some operations + "BC", "DE", "HL", "AF" }; // for push/pop + +static char *cond[] = +{ "NZ", "Z", "NC", "C" }; + +static char hexDigits[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +static GBOPCODE opcodes[] = { + { 0xff, 0x00, "NOP" }, + { 0xcf, 0x01, "LD %R4,%W" }, + { 0xff, 0x02, "LD (BC),A" }, + { 0xcf, 0x03, "INC %R4" }, + { 0xc7, 0x04, "INC %r3" }, + { 0xc7, 0x05, "DEC %r3" }, + { 0xc7, 0x06, "LD %r3,%B" }, + { 0xff, 0x07, "RLCA" }, + { 0xff, 0x08, "LD (%W),SP" }, + { 0xcf, 0x09, "ADD HL,%R4" }, + { 0xff, 0x0a, "LD A,(BC)" }, + { 0xcf, 0x0b, "DEC %R4" }, + { 0xff, 0x0f, "RRCA" }, + { 0xff, 0x10, "STOP" }, + { 0xff, 0x12, "LD (DE),A" }, + { 0xff, 0x17, "RLA" }, + { 0xff, 0x18, "JR %d" }, + { 0xff, 0x1a, "LD A,(DE)" }, + { 0xff, 0x1f, "RRA" }, + { 0xe7, 0x20, "JR %c3,%d" }, + { 0xff, 0x22, "LDI (HL),A" }, + { 0xff, 0x27, "DAA" }, + { 0xff, 0x2a, "LDI A,(HL)" }, + { 0xff, 0x2f, "CPL" }, + { 0xff, 0x32, "LDD (HL),A" }, + { 0xff, 0x37, "SCF" }, + { 0xff, 0x3a, "LDD A,(HL)" }, + { 0xff, 0x3f, "CCF" }, + { 0xff, 0x76, "HALT" }, + { 0xc0, 0x40, "LD %r3,%r0" }, + { 0xf8, 0x80, "ADD A,%r0" }, + { 0xf8, 0x88, "ADC A,%r0" }, + { 0xf8, 0x90, "SUB %r0" }, + { 0xf8, 0x98, "SBC A,%r0" }, + { 0xf8, 0xa0, "AND %r0" }, + { 0xf8, 0xa8, "XOR %r0" }, + { 0xf8, 0xb0, "OR %r0" }, + { 0xf8, 0xb8, "CP %r0" }, + { 0xe7, 0xc0, "RET %c3" }, + { 0xcf, 0xc1, "POP %t4" }, + { 0xe7, 0xc2, "JP %c3,%W" }, + { 0xff, 0xc3, "JP %W" }, + { 0xe7, 0xc4, "CALL %c3,%W" }, + { 0xcf, 0xc5, "PUSH %t4" }, + { 0xff, 0xc6, "ADD A,%B" }, + { 0xc7, 0xc7, "RST %P" }, + { 0xff, 0xc9, "RET" }, + { 0xff, 0xcd, "CALL %W" }, + { 0xff, 0xce, "ADC %B" }, + { 0xff, 0xd6, "SUB %B" }, + { 0xff, 0xd9, "RETI" }, + { 0xff, 0xde, "SBC %B" }, + { 0xff, 0xe0, "LD (FF%B),A" }, + { 0xff, 0xe2, "LD (FF00h+C),A" }, + { 0xff, 0xe6, "AND %B" }, + { 0xff, 0xe8, "ADD SP,%D" }, + { 0xff, 0xe9, "LD PC,HL" }, + { 0xff, 0xea, "LD (%W),A" }, + { 0xff, 0xee, "XOR %B" }, + { 0xff, 0xf0, "LD A,(FF%B)" }, + { 0xff, 0xf2, "LD A,(FF00h+C)" }, + { 0xff, 0xf3, "DI" }, + { 0xff, 0xf6, "OR %B" }, + { 0xff, 0xf8, "LD HL,SP%D" }, + { 0xff, 0xf9, "LD SP,HL" }, + { 0xff, 0xfa, "LD A,(%W)" }, + { 0xff, 0xfb, "EI" }, + { 0xff, 0xfe, "CP %B" }, + { 0x00, 0x00, "DB %B" } +}; + +static GBOPCODE cbOpcodes[] = { + { 0xf8, 0x00, "RLC %r0" }, + { 0xf8, 0x08, "RRC %r0" }, + { 0xf8, 0x10, "RL %r0" }, + { 0xf8, 0x18, "RR %r0" }, + { 0xf8, 0x20, "SLA %r0" }, + { 0xf8, 0x28, "SRA %r0" }, + { 0xf8, 0x30, "SWAP %r0" }, + { 0xf8, 0x38, "SRL %r0" }, + { 0xc0, 0x40, "BIT %b,%r0" }, + { 0xc0, 0x80, "RES %b,%r0" }, + { 0xc0, 0xc0, "SET %b,%r0" }, + { 0x00, 0x00, "DB CBh,%B" } +}; + +static char *addHex(char *p, u8 value) +{ + *p++ = hexDigits[value >> 4]; + *p++ = hexDigits[value & 15]; + return p; +} + +static char *addHex16(char *p, u16 value) +{ + p = addHex(p, value>>8); + return addHex(p, value & 255); +} + +static char *addStr(char *p, char *s) +{ + while (*s) + { + *p++ = *s++; + } + return p; +} + +int gbDis(char *buffer, u16 address) +{ + char *p = buffer; + int instr = 1; + u16 addr = address; + sprintf(p, "%04x ", address); + p += 12; + + u8 opcode = gbReadMemoryQuick(address); + address++; + char * mnen; + GBOPCODE *op; + if (opcode == 0xcb) + { + opcode = gbReadMemoryQuick(address); + address++; + instr++; + op = cbOpcodes; + } + else + { + op = opcodes; + } + while (op->value != (opcode & op->mask)) + op++; + mnen = op->mnen; + + u8 b0, b1; + s8 disp; + int shift; + + while (*mnen) + { + if (*mnen == '%') + { + mnen++; + switch (*mnen++) + { + case 'W': + b0 = gbReadMemoryQuick(address); + address++; + b1 = gbReadMemoryQuick(address); + address++; + p = addHex16(p, b0|b1<<8); + instr += 2; + *p++ = 'h'; + break; + case 'B': + p = addHex(p, gbReadMemoryQuick(address)); + *p++ = 'h'; + address++; + instr++; + break; + case 'D': + disp = gbReadMemoryQuick(address); + if (disp >= 0) + *p++ = '+'; + p += sprintf(p, "%d", disp); + instr++; + break; + case 'd': + disp = gbReadMemoryQuick(address); + address++; + p = addHex16(p, address+disp); + *p++ = 'h'; + instr++; + break; + case 'b': + // kind of a hack, but it works :-) + *p++ = hexDigits[(opcode >> 3) & 7]; + break; + case 'r': + shift = *mnen++ - '0'; + p = addStr(p, registers[(opcode >> shift) & 7]); + break; + case 'R': + shift = *mnen++ - '0'; + p = addStr(p, registers16[(opcode >> shift) & 3]); + break; + case 't': + shift = *mnen++ - '0'; + p = addStr(p, registers16[4+((opcode >> shift) & 3)]); + break; + case 'P': + p = addHex(p, ((opcode >> 3) & 7) * 8); + break; + case 'c': + shift = *mnen++ - '0'; + p = addStr(p, cond[(opcode >> shift) & 3]); + break; + } + } + else + *p++ = *mnen++; + } + for (int i = 0; i < instr; i++) + { + u16 a = addr + i; + addHex(buffer+5+i*2, gbReadMemoryQuick(a)); + } + *p = 0; + return instr; +} diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbGfx.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbGfx.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,552 @@ +#include + +#include "gbGlobals.h" +#include "gbSGB.h" + +extern int32 layerSettings; + +u8 gbInvertTab[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +u16 gbLineMix[160]; + +void gbRenderLine() +{ + u8 *bank0; + u8 *bank1; + if (gbCgbMode) + { + bank0 = &gbVram[0x0000]; + bank1 = &gbVram[0x2000]; + } + else + { + bank0 = &gbMemory[0x8000]; + bank1 = NULL; + } + + int tile_map = 0x1800; + if ((register_LCDC & 8) != 0) + tile_map = 0x1c00; + + int tile_pattern = 0x0800; + + if ((register_LCDC & 16) != 0) + tile_pattern = 0x0000; + + int x = 0; + int y = register_LY; + + if (y >= 144) + return; + + // int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip; + + int sx = register_SCX; + int sy = register_SCY; + + sy += y; + + sy &= 255; + + int tx = sx >> 3; + int ty = sy >> 3; + + int bx = 1 << (7 - (sx & 7)); + int by = sy & 7; + + int tile_map_line_y = tile_map + ty * 32; + + int tile_map_address = tile_map_line_y + tx; + + u8 attrs = 0; + if (bank1 != NULL) + attrs = bank1[tile_map_address]; + + u8 tile = bank0[tile_map_address]; + + tile_map_address++; + + if ((register_LCDC & 16) == 0) + { + if (tile < 128) + tile += 128; + else + tile -= 128; + } + + int tile_pattern_address = tile_pattern + tile * 16 + by*2; + + if (register_LCDC & 0x80) + { + if ((register_LCDC & 0x01 || gbCgbMode) && (layerSettings & 0x0100)) + { + while (x < 160) + { + u8 tile_a = 0; + u8 tile_b = 0; + + if (attrs & 0x40) + { + tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2; + } + + if (attrs & 0x08) + { + tile_a = bank1[tile_pattern_address++]; + tile_b = bank1[tile_pattern_address]; + } + else + { + tile_a = bank0[tile_pattern_address++]; + tile_b = bank0[tile_pattern_address]; + } + + if (attrs & 0x20) + { + tile_a = gbInvertTab[tile_a]; + tile_b = gbInvertTab[tile_b]; + } + + while (bx > 0) + { + u8 c = (tile_a & bx) ? 1 : 0; + c += ((tile_b & bx) ? 2 : 0); + + gbLineBuffer[x] = c; // mark the gbLineBuffer color + + if (attrs & 0x80) + gbLineBuffer[x] |= 0x300; + + if (gbCgbMode) + { + c = c + (attrs & 7)*4; + } + else + { + c = gbBgp[c]; + if (gbSgbMode && !gbCgbMode) + { + int dx = x >> 3; + int dy = y >> 3; + + int palette = gbSgbATF[dy * 20 + dx]; + + if (c == 0) + palette = 0; + + c = c + 4*palette; + } + } + gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c]] : + gbPalette[c]; + x++; + if (x >= 160) + break; + bx >>= 1; + } + tx++; + if (tx == 32) + tx = 0; + bx = 128; + + if (bank1) + attrs = bank1[tile_map_line_y + tx]; + + tile = bank0[tile_map_line_y + tx]; + + if ((register_LCDC & 16) == 0) + { + if (tile < 128) + tile += 128; + else + tile -= 128; + } + tile_pattern_address = tile_pattern + tile * 16 + by * 2; + } + } + else + { + for (int i = 0; i < 160; i++) + { + gbLineMix[i] = gbPalette[0]; + gbLineBuffer[i] = 0; + } + } + + // do the window display + if ((register_LCDC & 0x20) && (layerSettings & 0x2000)) + { + int wy = register_WY; + + if (y >= wy) + { + int wx = register_WX; + wx -= 7; + + if (wx <= 159 && gbWindowLine <= 143) + { + tile_map = 0x1800; + + if ((register_LCDC & 0x40) != 0) + tile_map = 0x1c00; + + if (gbWindowLine == -1) + { + gbWindowLine = 0; + } + + tx = 0; + ty = gbWindowLine >> 3; + + bx = 128; + by = gbWindowLine & 7; + + if (wx < 0) + { + bx >>= (-wx); + wx = 0; + } + + tile_map_line_y = tile_map + ty * 32; + + tile_map_address = tile_map_line_y + tx; + + x = wx; + + tile = bank0[tile_map_address]; + u8 attrs = 0; + if (bank1) + attrs = bank1[tile_map_address]; + tile_map_address++; + + if ((register_LCDC & 16) == 0) + { + if (tile < 128) + tile += 128; + else + tile -= 128; + } + + tile_pattern_address = tile_pattern + tile * 16 + by*2; + + while (x < 160) + { + u8 tile_a = 0; + u8 tile_b = 0; + + if (attrs & 0x40) + { + tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2; + } + + if (attrs & 0x08) + { + tile_a = bank1[tile_pattern_address++]; + tile_b = bank1[tile_pattern_address]; + } + else + { + tile_a = bank0[tile_pattern_address++]; + tile_b = bank0[tile_pattern_address]; + } + + if (attrs & 0x20) + { + tile_a = gbInvertTab[tile_a]; + tile_b = gbInvertTab[tile_b]; + } + + while (bx > 0) + { + u8 c = (tile_a & bx) != 0 ? 1 : 0; + c += ((tile_b & bx) != 0 ? 2 : 0); + + if (attrs & 0x80) + gbLineBuffer[x] = 0x300 + c; + else + gbLineBuffer[x] = 0x100 + c; + + if (gbCgbMode) + { + c = c + (attrs & 7) * 4; + } + else + { + c = gbBgp[c]; + if (gbSgbMode && !gbCgbMode) + { + int dx = x >> 3; + int dy = y >> 3; + + int palette = gbSgbATF[dy * 20 + dx]; + + if (c == 0) + palette = 0; + + c = c + 4*palette; + } + } + gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c]] : + gbPalette[c]; + x++; + if (x >= 160) + break; + bx >>= 1; + } + tx++; + if (tx == 32) + tx = 0; + bx = 128; + tile = bank0[tile_map_line_y + tx]; + if (bank1) + attrs = bank1[tile_map_line_y + tx]; + + if ((register_LCDC & 16) == 0) + { + if (tile < 128) + tile += 128; + else + tile -= 128; + } + tile_pattern_address = tile_pattern + tile * 16 + by * 2; + } + gbWindowLine++; + } + } + } + } + else + { + for (int i = 0; i < 160; i++) + { + gbLineMix[i] = gbPalette[0]; + gbLineBuffer[i] = 0; + } + } +} + +void gbDrawSpriteTile(int tile, int x, int y, int t, int flags, + int size, int spriteNumber) +{ + u8 *bank0; + u8 *bank1; + if (gbCgbMode) + { + if (register_VBK & 1) + { + bank0 = &gbVram[0x0000]; + bank1 = &gbVram[0x2000]; + } + else + { + bank0 = &gbVram[0x0000]; + bank1 = &gbVram[0x2000]; + } + } + else + { + bank0 = &gbMemory[0x8000]; + bank1 = NULL; + } + + int init = 0x0000; + + // int yLine = (y+gbBorderRowSkip) * gbBorderLineSkip; + + u8 *pal = gbObp0; + + int flipx = (flags & 0x20); + int flipy = (flags & 0x40); + + if ((flags & 0x10)) + pal = gbObp1; + + if (flipy) + { + t = (size ? 15 : 7) - t; + } + + int prio = flags & 0x80; + + int address = init + tile * 16 + 2*t; + int a = 0; + int b = 0; + + if (gbCgbMode && flags & 0x08) + { + a = bank1[address++]; + b = bank1[address++]; + } + else + { + a = bank0[address++]; + b = bank0[address++]; + } + + for (int xx = 0; xx < 8; xx++) + { + u8 mask = 1 << (7-xx); + u8 c = 0; + if ((a & mask)) + c++; + if ((b & mask)) + c += 2; + + if (c == 0) + continue; + + int xxx = xx+x; + if (flipx) + xxx = (7-xx+x); + + if (xxx < 0 || xxx > 159) + continue; + + u16 color = gbLineBuffer[xxx]; + + if (prio) + { + if (color < 0x200 && ((color & 0xFF) != 0)) + continue; + } + if (color >= 0x300 && color != 0x300) + continue; + else if (color >= 0x200 && color < 0x300) + { + int sprite = color & 0xff; + + int spriteX = gbMemory[0xfe00 + 4 * sprite + 1] - 8; + + if (spriteX == x) + { + if (sprite < spriteNumber) + continue; + } + else + { + if (gbCgbMode) + { + if (sprite < spriteNumber) + continue; + } + else + { + if (spriteX < x+8) + continue; + } + } + } + + gbLineBuffer[xxx] = 0x200 + spriteNumber; + + // make sure that sprites will work even in CGB mode + if (gbCgbMode) + { + c = c + (flags & 0x07)*4 + 32; + } + else + { + c = pal[c]; + + if (gbSgbMode && !gbCgbMode) + { + int dx = xxx >> 3; + int dy = y >> 3; + + int palette = gbSgbATF[dy * 20 + dx]; + + if (c == 0) + palette = 0; + + c = c + 4*palette; + } + else + { + c += 4; + } + } + + gbLineMix[xxx] = gbColorOption ? gbColorFilter[gbPalette[c]] : + gbPalette[c]; + } +} + +void gbDrawSprites() +{ + int x = 0; + int y = 0; + int count = 0; + + int size = (register_LCDC & 4); + + if (!(register_LCDC & 0x80)) + return; + + if ((register_LCDC & 2) && (layerSettings & 0x1000)) + { + int yc = register_LY; + + int address = 0xfe00; + for (int i = 0; i < 40; i++) + { + y = gbMemory[address++]; + x = gbMemory[address++]; + int tile = gbMemory[address++]; + if (size) + tile &= 254; + int flags = gbMemory[address++]; + + if (x > 0 && y > 0 && x < 168 && y < 160) + { + // check if sprite intersects current line + int t = yc -y + 16; + if (size && t >= 0 && t < 16) + { + gbDrawSpriteTile(tile, x-8, yc, t, flags, size, i); + count++; + } + else if (!size && t >= 0 && t < 8) + { + gbDrawSpriteTile(tile, x-8, yc, t, flags, size, i); + count++; + } + } + // sprite limit reached! + if (count >= 10) + break; + } + } +} diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbGlobals.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbGlobals.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,39 @@ +#include "../Port.h" +#include "GB.h" + +u8 *gbMemoryMap[16]; + +int32 gbRomSizeMask = 0; +int32 gbRomSize = 0; +int32 gbRamSizeMask = 0; +int32 gbRamSize = 0; + +u8 * gbMemory = NULL; +u8 * gbVram = NULL; +u8 * gbRom = NULL; +u8 * gbRam = NULL; +u8 * gbWram = NULL; +u16 *gbLineBuffer = NULL; + +u16 gbPalette[128]; +u8 gbBgp[4] = { 0, 1, 2, 3}; +u8 gbObp0[4] = { 0, 1, 2, 3}; +u8 gbObp1[4] = { 0, 1, 2, 3}; +int32 gbWindowLine = -1; + +int32 gbCgbMode = 0; + +u16 gbColorFilter[32768]; +int32 gbColorOption = 0; +int32 gbPaletteOption = 0; +int32 gbEmulatorType = 0; +int32 gbBorderOn = 1; +int32 gbBorderAutomatic = 0; +int32 gbBorderLineSkip = 160; +int32 gbBorderRowSkip = 0; +int32 gbBorderColumnSkip = 0; +int32 gbDmaTicks = 0; +bool8 gbNullInputHackEnabled = false; +bool8 gbNullInputHackTempEnabled = false; + +u8 (*gbSerialFunction)(u8) = NULL; diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbGlobals.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbGlobals.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,95 @@ +#ifndef VBA_GB_GLOBALS_H +#define VBA_GB_GLOBALS_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "../Port.h" + +extern int32 gbRomSizeMask; +extern int32 gbRomSize; +extern int32 gbRamSize; +extern int32 gbRamSizeMask; + +extern u8 * gbRom; +extern u8 * gbRam; +extern u8 * gbVram; +extern u8 * gbWram; +extern u8 * gbMemory; +extern u16 *gbLineBuffer; + +extern u8 *gbMemoryMap[16]; + +inline u8 gbReadMemoryQuick(u16 address) +{ + extern int32 gbEchoRAMFixOn; + if (gbEchoRAMFixOn) + { + if (address >= 0xe000 && address < 0xfe00) + { + address -= 0x2000; + } + } + return gbMemoryMap[address>>12][address&0xfff]; +} + +inline void gbWriteMemoryQuick(u16 address, u8 value) +{ + extern int32 gbEchoRAMFixOn; + if (gbEchoRAMFixOn) + { + if (address >= 0xe000 && address < 0xfe00) + { + address -= 0x2000; + } + } + gbMemoryMap[address>>12][address&0xfff] = value; +} + +inline u8 gbReadROMQuick(u32 address) +{ + return gbRom[address]; +} + +extern int32 gbFrameSkip; +extern u16 gbColorFilter[32768]; +extern int32 gbColorOption; +extern int32 gbPaletteOption; +extern int32 gbEmulatorType; +extern int32 gbBorderOn; +extern int32 gbBorderAutomatic; +extern int32 gbCgbMode; +extern int32 gbSgbMode; +extern int32 gbWindowLine; +extern int32 gbSpeed; +extern u8 gbBgp[4]; +extern u8 gbObp0[4]; +extern u8 gbObp1[4]; +extern u16 gbPalette[128]; + +extern u8 register_LCDC; +extern u8 register_LY; +extern u8 register_SCY; +extern u8 register_SCX; +extern u8 register_WY; +extern u8 register_WX; +extern u8 register_VBK; + +extern int emulating; + +extern int32 gbBorderLineSkip; +extern int32 gbBorderRowSkip; +extern int32 gbBorderColumnSkip; +extern int32 gbDmaTicks; + +extern bool8 useOldFrameTiming; +extern bool8 gbNullInputHackEnabled; +extern bool8 gbNullInputHackTempEnabled; + +extern void gbRenderLine(); +extern void gbDrawSprites(); + +extern u8 (*gbSerialFunction)(u8); + +#endif // VBA_GB_GLOBALS_H diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbMemory.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbMemory.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,1070 @@ +#include "gbGlobals.h" +#include "gbMemory.h" +#include "../common/System.h" +#include "../common/movie.h" + +mapperMBC1 gbDataMBC1 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // memory model + 0, // ROM high address + 0 // RAM address +}; + +// MBC1 ROM write registers +void mapperMBC1ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch (address & 0x6000) + { + case 0x0000: // RAM enable register + gbDataMBC1.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + // value = value & 0x1f; + if (value == 0) + value = 1; + if (value == gbDataMBC1.mapperROMBank) + break; + + tmpAddress = value << 14; + + // check current model + if (gbDataMBC1.mapperMemoryModel == 0) + { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; + } + + tmpAddress &= gbRomSizeMask; + gbDataMBC1.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select + if (gbDataMBC1.mapperMemoryModel == 1) + { + // 4/32 model, RAM bank switching provided + value = value & 0x03; + if (value == gbDataMBC1.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + gbDataMBC1.mapperRAMBank = value; + gbDataMBC1.mapperRAMAddress = tmpAddress; + } + else + { + // 16/8, set the high address + gbDataMBC1.mapperROMHighAddress = value & 0x03; + tmpAddress = gbDataMBC1.mapperROMBank << 14; + tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + break; + case 0x6000: // memory model select + gbDataMBC1.mapperMemoryModel = value & 1; + break; + } +} + +// MBC1 RAM write +void mapperMBC1RAM(u16 address, u8 value) +{ + if (gbDataMBC1.mapperRAMEnable) + { + if (gbRamSize) + { + gbWriteMemoryQuick(address, value); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +void memoryUpdateMapMBC1() +{ + int tmpAddress = gbDataMBC1.mapperROMBank << 14; + + // check current model + if (gbDataMBC1.mapperMemoryModel == 1) + { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; + } + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if (gbRamSize) + { + gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; + gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; + } +} + +mapperMBC2 gbDataMBC2 = { + 0, // RAM enable + 1 // ROM bank +}; + +// MBC2 ROM write registers +void mapperMBC2ROM(u16 address, u8 value) +{ + switch (address & 0x6000) + { + case 0x0000: // RAM enable + if (!(address & 0x0100)) + { + gbDataMBC2.mapperRAMEnable = (value & 0x0f) == 0x0a; + } + break; + case 0x2000: // ROM bank select + if (address & 0x0100) + { + value &= 0x0f; + + if (value == 0) + value = 1; + if (gbDataMBC2.mapperROMBank != value) + { + gbDataMBC2.mapperROMBank = value; + + int tmpAddress = value << 14; + + tmpAddress &= gbRomSizeMask; + + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + } + break; + } +} + +// MBC2 RAM write +void mapperMBC2RAM(u16 address, u8 value) +{ + if (gbDataMBC2.mapperRAMEnable) + { + if (gbRamSize && address < 0xa200) + { + gbWriteMemoryQuick(address, value); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +void memoryUpdateMapMBC2() +{ + int tmpAddress = gbDataMBC2.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; +} + +mapperMBC3 gbDataMBC3 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // RAM address + 0, // timer clock latch + 0, // timer clock register + 0, // timer seconds + 0, // timer minutes + 0, // timer hours + 0, // timer days + 0, // timer control + 0, // timer latched seconds + 0, // timer latched minutes + 0, // timer latched hours + 0, // timer latched days + 0, // timer latched control + (time_t)-1 // last time +}; + +void memoryUpdateMBC3Clock() +{ + time_t now; + + if (VBAMovieActive() || VBAMovieLoading()) + now = (time_t)(VBAMovieGetId() + VBAMovieGetFrameCounter()/60); /// FIXME: is /60 the right factor? + else + now = time(NULL); + + time_t diff = now - gbDataMBC3.mapperLastTime; + if (diff > 0) + { + // update the clock according to the last update time + gbDataMBC3.mapperSeconds += (int)(diff % 60); + if (gbDataMBC3.mapperSeconds > 59) + { + gbDataMBC3.mapperSeconds -= 60; + gbDataMBC3.mapperMinutes++; + } + + diff /= 60; + + gbDataMBC3.mapperMinutes += (int)(diff % 60); + if (gbDataMBC3.mapperMinutes > 60) + { + gbDataMBC3.mapperMinutes -= 60; + gbDataMBC3.mapperHours++; + } + + diff /= 60; + + gbDataMBC3.mapperHours += (int)(diff % 24); + if (gbDataMBC3.mapperHours > 24) + { + gbDataMBC3.mapperHours -= 24; + gbDataMBC3.mapperDays++; + } + diff /= 24; + + gbDataMBC3.mapperDays += (int)diff; + if (gbDataMBC3.mapperDays > 255) + { + if (gbDataMBC3.mapperDays > 511) + { + gbDataMBC3.mapperDays %= 512; + gbDataMBC3.mapperControl |= 0x80; + } + gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | + (gbDataMBC3.mapperDays > 255 ? 1 : 0); + } + } + gbDataMBC3.mapperLastTime = now; +} + +// MBC3 ROM write registers +void mapperMBC3ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch (address & 0x6000) + { + case 0x0000: // RAM enable register + gbDataMBC3.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + value = value & 0x7f; + if (value == 0) + value = 1; + if (value == gbDataMBC3.mapperROMBank) + break; + + tmpAddress = value << 14; + + tmpAddress &= gbRomSizeMask; + gbDataMBC3.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + break; + case 0x4000: // RAM bank select + if (value < 8) + { + if (value == gbDataMBC3.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + gbDataMBC3.mapperRAMBank = value; + gbDataMBC3.mapperRAMAddress = tmpAddress; + } + else + { + if (gbDataMBC3.mapperRAMEnable) + { + gbDataMBC3.mapperRAMBank = -1; + + gbDataMBC3.mapperClockRegister = value; + } + } + break; + case 0x6000: // clock latch + if (gbDataMBC3.mapperClockLatch == 0 && value == 1) + { + memoryUpdateMBC3Clock(); + gbDataMBC3.mapperLSeconds = gbDataMBC3.mapperSeconds; + gbDataMBC3.mapperLMinutes = gbDataMBC3.mapperMinutes; + gbDataMBC3.mapperLHours = gbDataMBC3.mapperHours; + gbDataMBC3.mapperLDays = gbDataMBC3.mapperDays; + gbDataMBC3.mapperLControl = gbDataMBC3.mapperControl; + } + if (value == 0x00 || value == 0x01) + gbDataMBC3.mapperClockLatch = value; + break; + } +} + +// MBC3 RAM write +void mapperMBC3RAM(u16 address, u8 value) +{ + if (gbDataMBC3.mapperRAMEnable) + { + if (gbDataMBC3.mapperRAMBank != -1) + { + if (gbRamSize) + { + gbWriteMemoryQuick(address, value); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } + else + { + time_t tmp; //Small kludge to get it working on some 64 bit systems. + if (VBAMovieActive() || VBAMovieLoading()) + gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter()/60; + else { + time(&tmp); + gbDataMBC3.mapperLastTime=(u32)tmp; + } + systemScreenMessage(ctime(&tmp), 4); + gbDataMBC3.mapperLastTime=(u32)tmp; + + switch (gbDataMBC3.mapperClockRegister) + { + case 0x08: + gbDataMBC3.mapperSeconds = value; + break; + case 0x09: + gbDataMBC3.mapperMinutes = value; + break; + case 0x0a: + gbDataMBC3.mapperHours = value; + break; + case 0x0b: + gbDataMBC3.mapperDays = value; + break; + case 0x0c: + if (gbDataMBC3.mapperControl & 0x80) + gbDataMBC3.mapperControl = 0x80 | value; + else + gbDataMBC3.mapperControl = value; + break; + } + } + } +} + +// MBC3 read RAM +u8 mapperMBC3ReadRAM(u16 address) +{ + if (gbDataMBC3.mapperRAMEnable) + { + if (gbDataMBC3.mapperRAMBank != -1) + { + return gbReadMemoryQuick(address); + } + + switch (gbDataMBC3.mapperClockRegister) + { + case 0x08: + return gbDataMBC3.mapperLSeconds; + break; + case 0x09: + return gbDataMBC3.mapperLMinutes; + break; + case 0x0a: + return gbDataMBC3.mapperLHours; + break; + case 0x0b: + return gbDataMBC3.mapperLDays; + break; + case 0x0c: + return gbDataMBC3.mapperLControl; + } + } + return 0; +} + +void memoryUpdateMapMBC3() +{ + int tmpAddress = gbDataMBC3.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if (gbDataMBC3.mapperRAMBank >= 0 && gbRamSize) + { + tmpAddress = gbDataMBC3.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + +mapperMBC5 gbDataMBC5 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // ROM high address + 0, // RAM address + 0 // is rumble cartridge? +}; + +// MBC5 ROM write registers +void mapperMBC5ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch (address & 0x6000) + { + case 0x0000: // RAM enable register + gbDataMBC5.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + if (address < 0x3000) + { + value = value & 0xff; + if (value == gbDataMBC5.mapperROMBank) + break; + + tmpAddress = (value << 14) | (gbDataMBC5.mapperROMHighAddress << 22) ; + + tmpAddress &= gbRomSizeMask; + gbDataMBC5.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + else + { + value = value & 1; + if (value == gbDataMBC5.mapperROMHighAddress) + break; + + tmpAddress = (gbDataMBC5.mapperROMBank << 14) | (value << 22); + + tmpAddress &= gbRomSizeMask; + gbDataMBC5.mapperROMHighAddress = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + break; + case 0x4000: // RAM bank select + if (gbDataMBC5.isRumbleCartridge) + value &= 0x07; + else + value &= 0x0f; + if (value == gbDataMBC5.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + if (gbRamSize) + { + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + + gbDataMBC5.mapperRAMBank = value; + gbDataMBC5.mapperRAMAddress = tmpAddress; + } + break; + } +} + +// MBC5 RAM write +void mapperMBC5RAM(u16 address, u8 value) +{ + if (gbDataMBC5.mapperRAMEnable) + { + if (gbRamSize) + { + gbWriteMemoryQuick(address, value); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +void memoryUpdateMapMBC5() +{ + int tmpAddress = (gbDataMBC5.mapperROMBank << 14) | + (gbDataMBC5.mapperROMHighAddress << 22) ; + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if (gbRamSize) + { + tmpAddress = gbDataMBC5.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + +mapperMBC7 gbDataMBC7 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // RAM address + 0, // chip select + 0, // ?? + 0, // mapper state + 0, // buffer for receiving serial data + 0, // idle state + 0, // count of bits received + 0, // command received + 0, // address received + 0, // write enable + 0, // value to return on ram +}; + +// MBC7 ROM write registers +void mapperMBC7ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch (address & 0x6000) + { + case 0x0000: + break; + case 0x2000: // ROM bank select + value = value & 0x7f; + if (value == 0) + value = 1; + + if (value == gbDataMBC7.mapperROMBank) + break; + + tmpAddress = (value << 14); + + tmpAddress &= gbRomSizeMask; + gbDataMBC7.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select/enable + if (value < 8) + { + tmpAddress = (value&3) << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + + gbDataMBC7.mapperRAMBank = value; + gbDataMBC7.mapperRAMAddress = tmpAddress; + gbDataMBC7.mapperRAMEnable = 0; + } + else + { + gbDataMBC7.mapperRAMEnable = 0; + } + break; + } +} + +// MBC7 read RAM +u8 mapperMBC7ReadRAM(u16 address) +{ + switch (address & 0xa0f0) + { + case 0xa000: + case 0xa010: + case 0xa060: + case 0xa070: + return 0; + case 0xa020: + // sensor X low byte + return systemGetSensorX() & 255; + case 0xa030: + // sensor X high byte + return systemGetSensorX() >> 8; + case 0xa040: + // sensor Y low byte + return systemGetSensorY() & 255; + case 0xa050: + // sensor Y high byte + return systemGetSensorY() >> 8; + case 0xa080: + return gbDataMBC7.value; + } + return 0xff; +} + +// MBC7 RAM write +void mapperMBC7RAM(u16 address, u8 value) +{ + if (address == 0xa080) + { + // special processing needed + int oldCs = gbDataMBC7.cs, oldSk = gbDataMBC7.sk; + + gbDataMBC7.cs = value>>7; + gbDataMBC7.sk = (value>>6)&1; + + if (!oldCs && gbDataMBC7.cs) + { + if (gbDataMBC7.state == 5) + { + if (gbDataMBC7.writeEnable) + { + gbWriteMemoryQuick(0xa000+gbDataMBC7.address*2, gbDataMBC7.buffer>>8); + gbWriteMemoryQuick(0xa000+gbDataMBC7.address*2+1, gbDataMBC7.buffer&0xff); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + gbDataMBC7.state = 0; + gbDataMBC7.value = 1; + } + else + { + gbDataMBC7.idle = true; + gbDataMBC7.state = 0; + } + } + + if (!oldSk && gbDataMBC7.sk) + { + if (gbDataMBC7.idle) + { + if (value & 0x02) + { + gbDataMBC7.idle = false; + gbDataMBC7.count = 0; + gbDataMBC7.state = 1; + } + } + else + { + switch (gbDataMBC7.state) + { + case 1: + // receiving command + gbDataMBC7.buffer <<= 1; + gbDataMBC7.buffer |= (value & 0x02) ? 1 : 0; + gbDataMBC7.count++; + if (gbDataMBC7.count == 2) + { + // finished receiving command + gbDataMBC7.state = 2; + gbDataMBC7.count = 0; + gbDataMBC7.code = gbDataMBC7.buffer & 3; + } + break; + case 2: + // receive address + gbDataMBC7.buffer <<= 1; + gbDataMBC7.buffer |= (value&0x02) ? 1 : 0; + gbDataMBC7.count++; + if (gbDataMBC7.count == 8) + { + // finish receiving + gbDataMBC7.state = 3; + gbDataMBC7.count = 0; + gbDataMBC7.address = gbDataMBC7.buffer&0xff; + if (gbDataMBC7.code == 0) + { + if ((gbDataMBC7.address>>6) == 0) + { + gbDataMBC7.writeEnable = 0; + gbDataMBC7.state = 0; + } + else if ((gbDataMBC7.address>>6) == 3) + { + gbDataMBC7.writeEnable = 1; + gbDataMBC7.state = 0; + } + } + } + break; + case 3: + gbDataMBC7.buffer <<= 1; + gbDataMBC7.buffer |= (value&0x02) ? 1 : 0; + gbDataMBC7.count++; + + switch (gbDataMBC7.code) + { + case 0: + if (gbDataMBC7.count == 16) + { + if ((gbDataMBC7.address>>6) == 0) + { + gbDataMBC7.writeEnable = 0; + gbDataMBC7.state = 0; + } + else if ((gbDataMBC7.address>>6) == 1) + { + if (gbDataMBC7.writeEnable) + { + for (int i = 0; i < 256; i++) + { + gbWriteMemoryQuick(0xa000+i*2, gbDataMBC7.buffer >> 8); + gbWriteMemoryQuick(0xa000+i*2+1, gbDataMBC7.buffer & 0xff); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } + gbDataMBC7.state = 5; + } + else if ((gbDataMBC7.address>>6) == 2) + { + if (gbDataMBC7.writeEnable) + { + for (int i = 0; i < 256; i++) + WRITE16LE((u16 *)&gbMemory[0xa000+i*2], 0xffff); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + gbDataMBC7.state = 5; + } + else if ((gbDataMBC7.address>>6) == 3) + { + gbDataMBC7.writeEnable = 1; + gbDataMBC7.state = 0; + } + gbDataMBC7.count = 0; + } + break; + case 1: + if (gbDataMBC7.count == 16) + { + gbDataMBC7.count = 0; + gbDataMBC7.state = 5; + gbDataMBC7.value = 0; + } + break; + case 2: + if (gbDataMBC7.count == 1) + { + gbDataMBC7.state = 4; + gbDataMBC7.count = 0; + gbDataMBC7.buffer = (gbReadMemoryQuick(0xa000+gbDataMBC7.address*2)<<8)| + (gbReadMemoryQuick(0xa000+gbDataMBC7.address*2+1)); + } + break; + case 3: + if (gbDataMBC7.count == 16) + { + gbDataMBC7.count = 0; + gbDataMBC7.state = 5; + gbDataMBC7.value = 0; + gbDataMBC7.buffer = 0xffff; + } + break; + } + break; + } + } + } + + if (oldSk && !gbDataMBC7.sk) + { + if (gbDataMBC7.state == 4) + { + gbDataMBC7.value = (gbDataMBC7.buffer & 0x8000) ? 1 : 0; + gbDataMBC7.buffer <<= 1; + gbDataMBC7.count++; + if (gbDataMBC7.count == 16) + { + gbDataMBC7.count = 0; + gbDataMBC7.state = 0; + } + } + } + } +} + +void memoryUpdateMapMBC7() +{ + int tmpAddress = (gbDataMBC5.mapperROMBank << 14); + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; +} + +mapperHuC1 gbDataHuC1 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // memory model + 0, // ROM high address + 0 // RAM address +}; + +// HuC1 ROM write registers +void mapperHuC1ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch (address & 0x6000) + { + case 0x0000: // RAM enable register + gbDataHuC1.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); + break; + case 0x2000: // ROM bank select + value = value & 0x3f; + if (value == 0) + value = 1; + if (value == gbDataHuC1.mapperROMBank) + break; + + tmpAddress = value << 14; + + tmpAddress &= gbRomSizeMask; + gbDataHuC1.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select + if (gbDataHuC1.mapperMemoryModel == 1) + { + // 4/32 model, RAM bank switching provided + value = value & 0x03; + if (value == gbDataHuC1.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + gbDataHuC1.mapperRAMBank = value; + gbDataHuC1.mapperRAMAddress = tmpAddress; + } + else + { + // 16/8, set the high address + gbDataHuC1.mapperROMHighAddress = value & 0x03; + tmpAddress = gbDataHuC1.mapperROMBank << 14; + tmpAddress |= (gbDataHuC1.mapperROMHighAddress) << 19; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + break; + case 0x6000: // memory model select + gbDataHuC1.mapperMemoryModel = value & 1; + break; + } +} + +// HuC1 RAM write +void mapperHuC1RAM(u16 address, u8 value) +{ + if (gbDataHuC1.mapperRAMEnable) + { + if (gbRamSize) + { + gbWriteMemoryQuick(address, value); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } +} + +void memoryUpdateMapHuC1() +{ + int tmpAddress = gbDataHuC1.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if (gbRamSize) + { + tmpAddress = gbDataHuC1.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + +mapperHuC3 gbDataHuC3 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // RAM address + 0, // RAM flag + 0 // RAM read value +}; + +// HuC3 ROM write registers +void mapperHuC3ROM(u16 address, u8 value) +{ + int tmpAddress = 0; + + switch (address & 0x6000) + { + case 0x0000: // RAM enable register + gbDataHuC3.mapperRAMEnable = (value == 0x0a ? 1 : 0); + gbDataHuC3.mapperRAMFlag = value; + if (gbDataHuC3.mapperRAMFlag != 0x0a) + gbDataHuC3.mapperRAMBank = -1; + break; + case 0x2000: // ROM bank select + value = value & 0x7f; + if (value == 0) + value = 1; + if (value == gbDataHuC3.mapperROMBank) + break; + + tmpAddress = value << 14; + + tmpAddress &= gbRomSizeMask; + gbDataHuC3.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + break; + case 0x4000: // RAM bank select + value = value & 0x03; + if (value == gbDataHuC3.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + gbDataHuC3.mapperRAMBank = value; + gbDataHuC3.mapperRAMAddress = tmpAddress; + break; + case 0x6000: // nothing to do! + break; + } +} + +// HuC3 read RAM +u8 mapperHuC3ReadRAM(u16 address) +{ + if (gbDataHuC3.mapperRAMFlag > 0x0b && + gbDataHuC3.mapperRAMFlag < 0x0e) + { + if (gbDataHuC3.mapperRAMFlag != 0x0c) + return 1; + return gbDataHuC3.mapperRAMValue; + } + else + return gbReadMemoryQuick(address); +} + +// HuC3 RAM write +void mapperHuC3RAM(u16 address, u8 value) +{ + int32 *p; + + if (gbDataHuC3.mapperRAMFlag < 0x0b || + gbDataHuC3.mapperRAMFlag > 0x0e) + { + if (gbDataHuC3.mapperRAMEnable) + { + if (gbRamSize) + { + gbWriteMemoryQuick(address, value); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } + } + else + { + if (gbDataHuC3.mapperRAMFlag == 0x0b) + { + if (value == 0x62) + { + gbDataHuC3.mapperRAMValue = 1; + } + else + { + switch (value & 0xf0) + { + case 0x10: + p = &gbDataHuC3.mapperRegister2; + gbDataHuC3.mapperRAMValue = *(p+gbDataHuC3.mapperRegister1++); + if (gbDataHuC3.mapperRegister1 > 6) + gbDataHuC3.mapperRegister1 = 0; + break; + case 0x30: + p = &gbDataHuC3.mapperRegister2; + *(p+gbDataHuC3.mapperRegister1++) = value & 0x0f; + if (gbDataHuC3.mapperRegister1 > 6) + gbDataHuC3.mapperRegister1 = 0; + gbDataHuC3.mapperAddress = + (gbDataHuC3.mapperRegister6 << 24) | + (gbDataHuC3.mapperRegister5 << 16) | + (gbDataHuC3.mapperRegister4 << 8) | + (gbDataHuC3.mapperRegister3 << 4) | + (gbDataHuC3.mapperRegister2); + break; + case 0x40: + gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0xf0) | + (value & 0x0f); + gbDataHuC3.mapperRegister2 = (gbDataHuC3.mapperAddress & 0x0f); + gbDataHuC3.mapperRegister3 = ((gbDataHuC3.mapperAddress>>4)&0x0f); + gbDataHuC3.mapperRegister4 = ((gbDataHuC3.mapperAddress>>8)&0x0f); + gbDataHuC3.mapperRegister5 = ((gbDataHuC3.mapperAddress>>16)&0x0f); + gbDataHuC3.mapperRegister6 = ((gbDataHuC3.mapperAddress>>24)&0x0f); + gbDataHuC3.mapperRegister7 = 0; + gbDataHuC3.mapperRegister8 = 0; + gbDataHuC3.mapperRAMValue = 0; + break; + case 0x50: + gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0x0f) | + ((value << 4)&0x0f); + break; + default: + gbDataHuC3.mapperRAMValue = 1; + break; + } + } + } + } +} + +void memoryUpdateMapHuC3() +{ + int tmpAddress = gbDataHuC3.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + if (gbRamSize) + { + tmpAddress = gbDataHuC3.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } +} + diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbMemory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbMemory.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,142 @@ +#ifndef VBA_GB_MEMORY_H +#define VBA_GB_MEMORY_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "../Port.h" + +struct mapperMBC1 +{ + int32 mapperRAMEnable; + int32 mapperROMBank; + int32 mapperRAMBank; + int32 mapperMemoryModel; + int32 mapperROMHighAddress; + int32 mapperRAMAddress; +}; + +struct mapperMBC2 +{ + int32 mapperRAMEnable; + int32 mapperROMBank; +}; + +struct mapperMBC3 +{ + int32 mapperRAMEnable; + int32 mapperROMBank; + int32 mapperRAMBank; + int32 mapperRAMAddress; + int32 mapperClockLatch; + int32 mapperClockRegister; + int32 mapperSeconds; + int32 mapperMinutes; + int32 mapperHours; + int32 mapperDays; + int32 mapperControl; + int32 mapperLSeconds; + int32 mapperLMinutes; + int32 mapperLHours; + int32 mapperLDays; + int32 mapperLControl; + //time_t mapperLastTime; + u32 mapperLastTime; +}; + +struct mapperMBC5 +{ + int32 mapperRAMEnable; + int32 mapperROMBank; + int32 mapperRAMBank; + int32 mapperROMHighAddress; + int32 mapperRAMAddress; + int32 isRumbleCartridge; +}; + +struct mapperMBC7 +{ + int32 mapperRAMEnable; + int32 mapperROMBank; + int32 mapperRAMBank; + int32 mapperRAMAddress; + int32 cs; + int32 sk; + int32 state; + int32 buffer; + int32 idle; + int32 count; + int32 code; + int32 address; + int32 writeEnable; + int32 value; +}; + +struct mapperHuC1 +{ + int32 mapperRAMEnable; + int32 mapperROMBank; + int32 mapperRAMBank; + int32 mapperMemoryModel; + int32 mapperROMHighAddress; + int32 mapperRAMAddress; +}; + +struct mapperHuC3 +{ + int32 mapperRAMEnable; + int32 mapperROMBank; + int32 mapperRAMBank; + int32 mapperRAMAddress; + int32 mapperAddress; + int32 mapperRAMFlag; + int32 mapperRAMValue; + int32 mapperRegister1; + int32 mapperRegister2; + int32 mapperRegister3; + int32 mapperRegister4; + int32 mapperRegister5; + int32 mapperRegister6; + int32 mapperRegister7; + int32 mapperRegister8; +}; + +extern mapperMBC1 gbDataMBC1; +extern mapperMBC2 gbDataMBC2; +extern mapperMBC3 gbDataMBC3; +extern mapperMBC5 gbDataMBC5; +extern mapperHuC1 gbDataHuC1; +extern mapperHuC3 gbDataHuC3; + +void mapperMBC1ROM(u16, u8); +void mapperMBC1RAM(u16, u8); +void mapperMBC2ROM(u16, u8); +void mapperMBC2RAM(u16, u8); +void mapperMBC3ROM(u16, u8); +void mapperMBC3RAM(u16, u8); +u8 mapperMBC3ReadRAM(u16); +void mapperMBC5ROM(u16, u8); +void mapperMBC5RAM(u16, u8); +void mapperMBC7ROM(u16, u8); +void mapperMBC7RAM(u16, u8); +u8 mapperMBC7ReadRAM(u16); +void mapperHuC1ROM(u16, u8); +void mapperHuC1RAM(u16, u8); +void mapperHuC3ROM(u16, u8); +void mapperHuC3RAM(u16, u8); +u8 mapperHuC3ReadRAM(u16); + +//extern void (*mapper)(u16,u8); +//extern void (*mapperRAM)(u16,u8); +//extern u8 (*mapperReadRAM)(u16); + +extern void memoryUpdateMapMBC1(); +extern void memoryUpdateMapMBC2(); +extern void memoryUpdateMapMBC3(); +extern void memoryUpdateMapMBC5(); +extern void memoryUpdateMapMBC7(); +extern void memoryUpdateMapHuC1(); +extern void memoryUpdateMapHuC3(); + +#endif // VBA_GB_MEMORY diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbPrinter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbPrinter.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,234 @@ +#include +#include + +#include "../common/System.h" +#include "gbPrinter.h" + +u8 gbPrinterStatus = 0; +int gbPrinterState = 0; +u8 gbPrinterData[0x280*9]; +u8 gbPrinterPacket[0x400]; +int gbPrinterCount = 0; +int gbPrinterDataCount = 0; +int gbPrinterDataSize = 0; +int gbPrinterResult = 0; + +bool gbPrinterCheckCRC() +{ + u16 crc = 0; + + for (int i = 2; i < (6+gbPrinterDataSize); i++) + { + crc += gbPrinterPacket[i]; + } + + int msgCrc = gbPrinterPacket[6+gbPrinterDataSize] + + (gbPrinterPacket[7+gbPrinterDataSize]<<8); + + return msgCrc == crc; +} + +void gbPrinterReset() +{ + gbPrinterState = 0; + gbPrinterDataSize = 0; + gbPrinterDataCount = 0; + gbPrinterCount = 0; + gbPrinterStatus = 0; + gbPrinterResult = 0; +} + +void gbPrinterShowData() +{ + systemGbPrint(gbPrinterData, + gbPrinterPacket[6], + gbPrinterPacket[7], + gbPrinterPacket[8], + gbPrinterPacket[9]); + /* + allegro_init(); + install_keyboard(); + set_gfx_mode(GFX_AUTODETECT, 160, 144, 0, 0); + PALETTE pal; + pal[0].r = 255; + pal[0].g = 255; + pal[0].b = 255; + pal[1].r = 168; + pal[1].g = 168; + pal[1].b = 168; + pal[2].r = 96; + pal[2].g = 96; + pal[2].b = 96; + pal[3].r = 0; + pal[3].g = 0; + pal[3].b = 0; + set_palette(pal); + acquire_screen(); + u8 *data = gbPrinterData; + for(int y = 0; y < 0x12; y++) { + for(int x = 0; x < 0x14; x++) { + for(int k = 0; k < 8; k++) { + int a = *data++; + int b = *data++; + for(int j = 0; j < 8; j++) { + int mask = 1 << (7-j); + int c = 0; + if(a & mask) + c++; + if(b & mask) + c+=2; + putpixel(screen, x*8+j, y*8+k, c); + } + } + } + } + release_screen(); + while(!keypressed()) { + } + */ +} + +void gbPrinterReceiveData() +{ + if (gbPrinterPacket[3]) // compressed + { + u8 *data = &gbPrinterPacket[6]; + u8 *dest = &gbPrinterData[gbPrinterDataCount]; + int len = 0; + while (len < gbPrinterDataSize) + { + u8 control = *data++; + if (control & 0x80) // repeated data + { + control &= 0x7f; + control += 2; + memset(dest, *data++, control); + len += control; + dest += control; + } + else // raw data + { + control++; + memcpy(dest, data, control); + dest += control; + data += control; + len += control; + } + } + } + else + { + memcpy(&gbPrinterData[gbPrinterDataCount], + &gbPrinterPacket[6], + gbPrinterDataSize); + gbPrinterDataCount += gbPrinterDataSize; + } +} + +void gbPrinterCommand() +{ + switch (gbPrinterPacket[2]) + { + case 0x01: + // reset/initialize packet + gbPrinterDataCount = 0; + gbPrinterStatus = 0; + break; + case 0x02: + // print packet + gbPrinterShowData(); + break; + case 0x04: + // data packet + gbPrinterReceiveData(); + break; + case 0x0f: + // NUL packet + break; + } +} + +u8 gbPrinterSend(u8 byte) +{ + switch (gbPrinterState) + { + case 0: + gbPrinterCount = 0; + // receiving preamble + if (byte == 0x88) + { + gbPrinterPacket[gbPrinterCount++] = byte; + gbPrinterState++; + } + else + { + // todo: handle failure + gbPrinterReset(); + } + break; + case 1: + // receiving preamble + if (byte == 0x33) + { + gbPrinterPacket[gbPrinterCount++] = byte; + gbPrinterState++; + } + else + { + // todo: handle failure + gbPrinterReset(); + } + break; + case 2: + // receiving header + gbPrinterPacket[gbPrinterCount++] = byte; + if (gbPrinterCount == 6) + { + gbPrinterState++; + gbPrinterDataSize = gbPrinterPacket[4] + (gbPrinterPacket[5]<<8); + } + break; + case 3: + // receiving data + if (gbPrinterDataSize) + { + gbPrinterPacket[gbPrinterCount++] = byte; + if (gbPrinterCount == (6+gbPrinterDataSize)) + { + gbPrinterState++; + } + break; + } + gbPrinterState++; + // intentionally move to next if no data to receive + case 4: + // receiving CRC + gbPrinterPacket[gbPrinterCount++] = byte; + gbPrinterState++; + break; + case 5: + // receiving CRC-2 + gbPrinterPacket[gbPrinterCount++] = byte; + if (gbPrinterCheckCRC()) + { + gbPrinterCommand(); + } + gbPrinterState++; + break; + case 6: + // receiving dummy 1 + gbPrinterPacket[gbPrinterCount++] = byte; + gbPrinterResult = 0x81; + gbPrinterState++; + break; + case 7: + // receiving dummy 2 + gbPrinterPacket[gbPrinterCount++] = byte; + gbPrinterResult = gbPrinterStatus; + gbPrinterState = 0; + gbPrinterCount = 0; + break; + } + return gbPrinterResult; +} + diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbPrinter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbPrinter.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,10 @@ +#ifndef VBA_GB_PRINTER_H +#define VBA_GB_PRINTER_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +extern u8 gbPrinterSend(u8 byte); + +#endif // VBA_GB_PRINTER_H diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbSGB.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbSGB.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,997 @@ +#include +#include + +#include "../common/System.h" +#include "../common/Util.h" +#include "GB.h" +#include "gbGlobals.h" +#include "../common/movie.h" + +extern u8 * pix; + +#define GBSGB_NONE 0 +#define GBSGB_RESET 1 +#define GBSGB_PACKET_TRANSMIT 2 + +u8 gbSgbBorderChar [32 * 256]; +u8 gbSgbBorder [2048]; + +int32 gbSgbCGBSupport = 0; +int32 gbSgbMask = 0; +int32 gbSgbMode = 0; +int32 gbSgbPacketState = GBSGB_NONE; +int32 gbSgbBit = 0; +int32 gbSgbPacketTimeout = 0; +int32 GBSGB_PACKET_TIMEOUT = 66666; +u8 gbSgbPacket[16 * 7]; +int32 gbSgbPacketNBits = 0; +int32 gbSgbPacketByte = 0; +int32 gbSgbPacketNumber = 0; +int32 gbSgbMultiplayer = 0; +int32 gbSgbFourPlayers = 0; +u8 gbSgbNextController = 0x0f; +u8 gbSgbReadingController = 0; +u16 gbSgbSCPPalette[4 * 512]; +u8 gbSgbATF[20 * 18]; +u8 gbSgbATFList[45 * 20 * 18]; +u8 gbSgbScreenBuffer[4160]; + +inline void gbSgbDraw24Bit(u8 *p, u16 v) +{ + *((u32 *) p) = systemColorMap32[v]; +} + +inline void gbSgbDraw32Bit(u32 *p, u16 v) +{ + *p = systemColorMap32[v]; +} + +inline void gbSgbDraw16Bit(u16 *p, u16 v) +{ + *p = systemColorMap16[v]; +} + +void gbSgbReset() +{ + gbSgbPacketTimeout = 0; + gbSgbCGBSupport = 0; + gbSgbMask = 0; + gbSgbPacketState = GBSGB_NONE; + gbSgbBit = 0; + gbSgbPacketNBits = 0; + gbSgbPacketNumber = 0; + gbSgbMultiplayer = 0; + gbSgbFourPlayers = 0; + gbSgbNextController = 0x0f; + gbSgbReadingController = 0; + + memset(gbSgbSCPPalette, 0, 512 * 4); + memset(gbSgbATF, 0, 20 * 18); + memset(gbSgbATFList, 0, 45 * 20 * 18); + memset(gbSgbPacket, 0, 16 * 7); + memset(gbSgbBorderChar, 0, 32 * 256); + memset(gbSgbBorder, 0, 2048); + + int i; + for (i = 1; i < 2048; i += 2) + { + gbSgbBorder[i] = 1 << 2; + } + + for (i = 0; i < 4; i++) + { + gbPalette[i * 4] = (0x1f) | (0x1f << 5) | (0x1f << 10); + gbPalette[i * 4 + 1] = (0x15) | (0x15 << 5) | (0x15 << 10); + gbPalette[i * 4 + 2] = (0x0c) | (0x0c << 5) | (0x0c << 10); + gbPalette[i * 4 + 3] = 0; + } +} + +void gbSgbInit() +{ + gbSgbReset(); +} + +void gbSgbShutdown() +{ + memset(gbSgbBorderChar, 0, 32 * 256); + memset(gbSgbBorder, 0, 2048); +} + +void gbSgbFillScreen(u16 color) +{ + switch (systemColorDepth) + { + case 16: + { + for (int y = 0; y < 144; y++) + { + int yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 2) + + gbBorderColumnSkip; + u16 *dest = (u16 *)pix + yLine; + for (register int x = 0; x < 160; x++) + gbSgbDraw16Bit(dest++, color); + } + } + break; + case 24: + { + for (int y = 0; y < 144; y++) + { + int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip + gbBorderColumnSkip; + u8 *dest = (u8 *)pix + yLine * 3; + for (register int x = 0; x < 160; x++) + { + gbSgbDraw24Bit(dest, color); + dest += 3; + } + } + } + break; + case 32: + { + for (int y = 0; y < 144; y++) + { + int yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 1) + gbBorderColumnSkip; + u32 *dest = (u32 *)pix + yLine; + for (register int x = 0; x < 160; x++) + { + gbSgbDraw32Bit(dest++, color); + } + } + } + break; + } +} + +void gbSgbRenderScreenToBuffer() +{ + u16 mapAddress = 0x9800; + + if (register_LCDC & 0x08) + mapAddress = 0x9c00; + + u16 patternAddress = 0x8800; + + int flag = 1; + + if (register_LCDC & 0x10) + { + patternAddress = 0x8000; + flag = 0; + } + + u8 *toAddress = gbSgbScreenBuffer; + + for (int i = 0; i < 13; i++) + { + for (int j = 0; j < 20; j++) + { + int tile = gbReadMemoryQuick(mapAddress); + mapAddress++; + + if (flag) + { + if (tile > 127) + tile -= 128; + else + tile += 128; + } + for (int k = 0; k < 16; k++) + *toAddress++ = gbReadMemoryQuick(patternAddress + tile * 16 + k); + } + mapAddress += 12; + } +} + +void gbSgbDrawBorderTile(int x, int y, int tile, int attr) +{ + u16 *dest = (u16 *)pix + ((y + 1) * (256 + 2)) + x; + u8 * dest8 = (u8 *)pix + ((y * 256) + x) * 3; + u32 *dest32 = (u32 *)pix + ((y + 1) * 257) + x; + + u8 *tileAddress = &gbSgbBorderChar[tile * 32]; + u8 *tileAddress2 = &gbSgbBorderChar[tile * 32 + 16]; + + u8 l = 8; + + u8 palette = ((attr >> 2) & 7); + + if (palette < 4) + palette += 4; + + palette *= 16; + + u8 xx = 0; + u8 yy = 0; + + int flipX = attr & 0x40; + int flipY = attr & 0x80; + + while (l > 0) + { + u8 mask = 0x80; + u8 a = *tileAddress++; + u8 b = *tileAddress++; + u8 c = *tileAddress2++; + u8 d = *tileAddress2++; + + while (mask > 0) + { + u8 color = 0; + if (a & mask) + color++; + if (b & mask) + color += 2; + if (c & mask) + color += 4; + if (d & mask) + color += 8; + + u8 xxx = xx; + u8 yyy = yy; + + if (flipX) + xxx = 7 - xx; + if (flipY) + yyy = 7 - yy; + + u8 realx = x + xxx; + u8 realy = y + yyy; + + u16 c = gbPalette[palette + color]; + if (!color) + c = gbPalette[0]; + if ((realy < 40 || realy >= 184) || (realx < 48 || realx >= 208)) + { + switch (systemColorDepth) + { + case 16: + gbSgbDraw16Bit(dest + yyy * (256 + 2) + xxx, c); + break; + case 24: + gbSgbDraw24Bit(dest8 + (yyy * 256 + xxx) * 3, c); + break; + case 32: + gbSgbDraw32Bit(dest32 + yyy * (256 + 1) + xxx, c); + break; + } + } + + mask >>= 1; + + xx++; + } + yy++; + xx = 0; + l--; + mask = 0x80; + } +} + +void gbSgbRenderBorder() +{ + if (gbBorderOn) + { + u8 *fromAddress = gbSgbBorder; + + for (u8 y = 0; y < 28; y++) + { + for (u8 x = 0; x < 32; x++) + { + u8 tile = *fromAddress++; + u8 attr = *fromAddress++; + + gbSgbDrawBorderTile(x * 8, y * 8, tile, attr); + } + } + } +} + +void gbSgbPicture() +{ + gbSgbRenderScreenToBuffer(); + + memcpy(gbSgbBorder, gbSgbScreenBuffer, 2048); + + u16 *paletteAddr = (u16 *)&gbSgbScreenBuffer[2048]; + + for (int i = 64; i < 128; i++) + { + gbPalette[i] = READ16LE(paletteAddr++); + } + + gbSgbCGBSupport |= 4; + + if (gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) + { + gbBorderOn = 1; + systemGbBorderOn(); + } + + if (gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); + + if (gbSgbMode && gbCgbMode && gbSgbCGBSupport > 4) + { + gbSgbCGBSupport = 0; + gbSgbMode = 2; + gbSgbMask = 0; + gbSgbRenderBorder(); + gbReset(); + } + + if (gbSgbCGBSupport > 4) + gbSgbCGBSupport = 0; +} + +void gbSgbSetPalette(int a, int b, u16 *p) +{ + u16 bit00 = READ16LE(p++); + int i; + + for (i = 1; i < 4; i++) + { + gbPalette[a * 4 + i] = READ16LE(p++); + } + + for (i = 1; i < 4; i++) + { + gbPalette[b * 4 + i] = READ16LE(p++); + } + + gbPalette[0] = gbPalette[4] = gbPalette[8] = gbPalette[12] = bit00; + if (gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); +} + +void gbSgbScpPalette() +{ + gbSgbRenderScreenToBuffer(); + + u16 *fromAddress = (u16 *)gbSgbScreenBuffer; + + for (int i = 0; i < 512 * 4; i++) + { + gbSgbSCPPalette[i] = READ16LE(fromAddress++); + } +} + +void gbSgbSetATF(int n) +{ + if (n < 0) + n = 0; + if (n > 44) + n = 44; + memcpy(gbSgbATF, &gbSgbATFList[n * 20 * 18], 20 * 18); + + if (gbSgbPacket[1] & 0x40) + { + gbSgbMask = 0; + if (gbBorderOn) + gbSgbRenderBorder(); + } +} + +void gbSgbSetPalette() +{ + u16 pal = READ16LE((((u16 *)&gbSgbPacket[1]))) & 511; + memcpy(&gbPalette[0], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16)); + + pal = READ16LE((((u16 *)&gbSgbPacket[3]))) & 511; + memcpy(&gbPalette[4], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16)); + + pal = READ16LE((((u16 *)&gbSgbPacket[5]))) & 511; + memcpy(&gbPalette[8], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16)); + + pal = READ16LE((((u16 *)&gbSgbPacket[7]))) & 511; + memcpy(&gbPalette[12], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16)); + + u8 atf = gbSgbPacket[9]; + + if (atf & 0x80) + { + gbSgbSetATF(atf & 0x3f); + } + + if (atf & 0x40) + { + gbSgbMask = 0; + if (gbBorderOn) + gbSgbRenderBorder(); + } +} + +void gbSgbAttributeBlock() +{ + u8 *fromAddress = &gbSgbPacket[1]; + + u8 nDataSet = *fromAddress++; + if (nDataSet > 12) + nDataSet = 12; + if (nDataSet == 0) + nDataSet = 1; + + while (nDataSet) + { + u8 controlCode = (*fromAddress++) & 7; + u8 paletteDesignation = (*fromAddress++) & 0x3f; + u8 startH = (*fromAddress++) & 0x1f; + u8 startV = (*fromAddress++) & 0x1f; + u8 endH = (*fromAddress++) & 0x1f; + u8 endV = (*fromAddress++) & 0x1f; + + u8 *toAddress = gbSgbATF; + + for (u8 y = 0; y < 18; y++) + { + for (u8 x = 0; x < 20; x++) + { + if (x < startH || y < startV || + x > endH || y > endV) + { + // outside + if (controlCode & 0x04) + *toAddress = (paletteDesignation >> 4) & 0x03; + } + else if (x > startH && x < endH && + y > startV && y < endV) + { + // inside + if (controlCode & 0x01) + *toAddress = paletteDesignation & 0x03; + } + else + { + // surrounding line + if (controlCode & 0x02) + *toAddress = (paletteDesignation >> 2) & 0x03; + else if (controlCode == 0x01) + *toAddress = paletteDesignation & 0x03; + } + toAddress++; + } + } + nDataSet--; + } +} + +void gbSgbSetColumnPalette(u8 col, u8 p) +{ + // if(col < 0) + // col = 0; + if (col > 19) + col = 19; + + p &= 3; + + u8 *toAddress = &gbSgbATF[col]; + + for (u8 y = 0; y < 18; y++) + { + *toAddress = p; + toAddress += 20; + } +} + +void gbSgbSetRowPalette(u8 row, u8 p) +{ + // if(row < 0) + // row = 0; + if (row > 17) + row = 17; + + p &= 3; + + u8 *toAddress = &gbSgbATF[row * 20]; + + for (u8 x = 0; x < 20; x++) + { + *toAddress++ = p; + } +} + +void gbSgbAttributeDivide() +{ + u8 control = gbSgbPacket[1]; + u8 coord = gbSgbPacket[2]; + u8 colorBR = control & 3; + u8 colorAL = (control >> 2) & 3; + u8 colorOL = (control >> 4) & 3; + + if (control & 0x40) + { + if (coord > 17) + coord = 17; + + for (u8 i = 0; i < 18; i++) + { + if (i < coord) + gbSgbSetRowPalette(i, colorAL); + else if (i > coord) + gbSgbSetRowPalette(i, colorBR); + else + gbSgbSetRowPalette(i, colorOL); + } + } + else + { + if (coord > 19) + coord = 19; + + for (u8 i = 0; i < 20; i++) + { + if (i < coord) + gbSgbSetColumnPalette(i, colorAL); + else if (i > coord) + gbSgbSetColumnPalette(i, colorBR); + else + gbSgbSetColumnPalette(i, colorOL); + } + } +} + +void gbSgbAttributeLine() +{ + u8 *fromAddress = &gbSgbPacket[1]; + + u8 nDataSet = *fromAddress++; + + if (nDataSet > 0x6e) + nDataSet = 0x6e; + + while (nDataSet) + { + u8 line = *fromAddress++; + u8 num = line & 0x1f; + u8 pal = (line >> 5) & 0x03; + if (line & 0x80) + { + if (num > 17) + num = 17; + gbSgbSetRowPalette(num, pal); + } + else + { + if (num > 19) + num = 19; + gbSgbSetColumnPalette(num, pal); + } + nDataSet--; + } +} + +void gbSgbAttributeCharacter() +{ + u8 startH = gbSgbPacket[1] & 0x1f; + u8 startV = gbSgbPacket[2] & 0x1f; + int nDataSet = READ16LE(((u16 *)&gbSgbPacket[3])); + int style = gbSgbPacket[5] & 1; + if (startH > 19) + startH = 19; + if (startV > 17) + startV = 17; + + u8 s = 6; + u8 *fromAddress = &gbSgbPacket[6]; + u8 v = *fromAddress++; + + if (style) + { + while (nDataSet) + { + u8 p = (v >> s) & 3; + gbSgbATF[startV * 20 + startH] = p; + startV++; + if (startV == 18) + { + startV = 0; + startH++; + if (startH == 20) + break; + } + + if (s) + s -= 2; + else + { + s = 6; + v = *fromAddress++; + nDataSet--; + } + } + } + else + { + while (nDataSet) + { + u8 p = (v >> s) & 3; + gbSgbATF[startV * 20 + startH] = p; + startH++; + if (startH == 20) + { + startH = 0; + startV++; + if (startV == 18) + break; + } + + if (s) + s -= 2; + else + { + s = 6; + v = *fromAddress++; + nDataSet--; + } + } + } +} + +void gbSgbSetATFList() +{ + gbSgbRenderScreenToBuffer(); + + u8 *fromAddress = gbSgbScreenBuffer; + u8 *toAddress = gbSgbATFList; + + for (int i = 0; i < 45; i++) + { + for (int j = 0; j < 90; j++) + { + u8 v = *fromAddress++; + u8 s = 6; + if (i == 2) + s = 6; + for (int k = 0; k < 4; k++) + { + *toAddress++ = (v >> s) & 0x03; + s -= 2; + } + } + } +} + +void gbSgbMaskEnable() +{ + int gbSgbMaskFlag = gbSgbPacket[1] & 3; + + gbSgbMask = gbSgbMaskFlag; + + switch (gbSgbMaskFlag) + { + case 1: + break; + case 2: + gbSgbFillScreen(0x0000); + // memset(&gbPalette[0], 0, 128*sizeof(u16)); + break; + case 3: + gbSgbFillScreen(gbPalette[0]); + break; + } + if (!gbSgbMask) + { + if (gbBorderOn) + gbSgbRenderBorder(); + } +} + +void gbSgbChrTransfer() +{ + gbSgbRenderScreenToBuffer(); + + int address = (gbSgbPacket[1] & 1) * (128 * 32); + + if (gbSgbPacket[1] & 1) + gbSgbCGBSupport |= 2; + else + gbSgbCGBSupport |= 1; + + memcpy(&gbSgbBorderChar[address], gbSgbScreenBuffer, 128 * 32); + + if (gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) + { + gbBorderOn = 1; + systemGbBorderOn(); + } + + if (gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); + + if (gbSgbMode && gbCgbMode && gbSgbCGBSupport == 7) + { + gbSgbCGBSupport = 0; + gbSgbMode = 2; + gbSgbMask = 0; + gbSgbRenderBorder(); + gbReset(); + } + + if (gbSgbCGBSupport > 4) + gbSgbCGBSupport = 0; +} + +void gbSgbMultiRequest() +{ + if (gbSgbPacket[1] & 1) + { + gbSgbMultiplayer = 1; + if (gbSgbPacket[1] & 2) + gbSgbFourPlayers = 1; + else + gbSgbFourPlayers = 0; + gbSgbNextController = 0x0e; + } + else + { + gbSgbFourPlayers = 0; + gbSgbMultiplayer = 0; + gbSgbNextController = 0x0f; + } +} + +void gbSgbCommand() +{ + int command = gbSgbPacket[0] >> 3; + // int nPacket = gbSgbPacket[0] & 7; + + switch (command) + { + case 0x00: + gbSgbSetPalette(0, 1, (u16 *)&gbSgbPacket[1]); + break; + case 0x01: + gbSgbSetPalette(2, 3, (u16 *)&gbSgbPacket[1]); + break; + case 0x02: + gbSgbSetPalette(0, 3, (u16 *)&gbSgbPacket[1]); + break; + case 0x03: + gbSgbSetPalette(1, 2, (u16 *)&gbSgbPacket[1]); + break; + case 0x04: + gbSgbAttributeBlock(); + break; + case 0x05: + gbSgbAttributeLine(); + break; + case 0x06: + gbSgbAttributeDivide(); + break; + case 0x07: + gbSgbAttributeCharacter(); + break; + case 0x0a: + gbSgbSetPalette(); + break; + case 0x0b: + gbSgbScpPalette(); + break; + case 0x11: + gbSgbMultiRequest(); + break; + case 0x13: + gbSgbChrTransfer(); + break; + case 0x14: + gbSgbPicture(); + break; + case 0x15: + gbSgbSetATFList(); + break; + case 0x16: + gbSgbSetATF(gbSgbPacket[1] & 0x3f); + break; + case 0x17: + gbSgbMaskEnable(); + break; + } +} + +void gbSgbResetPacketState() +{ + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; +} + +void gbSgbDoBitTransfer(u8 value) +{ + value = value & 0x30; + switch (gbSgbPacketState) + { + case GBSGB_NONE: + if (value == 0) + { + gbSgbPacketState = GBSGB_RESET; + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + } + else if (value == 0x30) + { + if (gbSgbMultiplayer) + { + if ((gbSgbReadingController & 7) == 7) + { + gbSgbReadingController = 0; + if (gbSgbMultiplayer) + { + gbSgbNextController--; + if (gbSgbFourPlayers) + { + if (gbSgbNextController == 0x0b) + gbSgbNextController = 0x0f; + } + else + { + if (gbSgbNextController == 0x0d) + gbSgbNextController = 0x0f; + } + } + } + else + { + gbSgbReadingController &= 3; + } + } + gbSgbPacketTimeout = 0; + } + else + { + if (value == 0x10) + gbSgbReadingController |= 0x2; + else if (value == 0x20) + gbSgbReadingController |= 0x01; + gbSgbPacketTimeout = 0; + } + gbSgbPacketTimeout = 0; + break; + case GBSGB_RESET: + if (value == 0x30) + { + gbSgbPacketState = GBSGB_PACKET_TRANSMIT; + gbSgbPacketByte = 0; + gbSgbPacketNBits = 0; + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + } + else if (value == 0x00) + { + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + gbSgbPacketState = GBSGB_RESET; + } + else + { + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; + } + break; + case GBSGB_PACKET_TRANSMIT: + if (value == 0) + { + gbSgbPacketState = GBSGB_RESET; + gbSgbPacketTimeout = 0; + } + else if (value == 0x30) + { + if (gbSgbPacketNBits == 128) + { + gbSgbPacketNBits = 0; + gbSgbPacketByte = 0; + gbSgbPacketNumber++; + gbSgbPacketTimeout = 0; + if (gbSgbPacketNumber == (gbSgbPacket[0] & 7)) + { + gbSgbCommand(); + gbSgbPacketNumber = 0; + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; + } + } + else + { + if (gbSgbPacketNBits < 128) + { + gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] >>= 1; + gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] |= gbSgbBit; + gbSgbPacketNBits++; + if (!(gbSgbPacketNBits & 7)) + { + gbSgbPacketByte++; + } + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + } + } + } + else + { + if (value == 0x20) + gbSgbBit = 0x00; + else + gbSgbBit = 0x80; + gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + } + gbSgbReadingController = 0; + break; + default: + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; + break; + } +} + +variable_desc gbSgbSaveStruct[] = { + { &gbSgbMask, sizeof(int32) }, + { &gbSgbPacketState, sizeof(int32) }, + { &gbSgbBit, sizeof(int32) }, + { &gbSgbPacketNBits, sizeof(int32) }, + { &gbSgbPacketByte, sizeof(int32) }, + { &gbSgbPacketNumber, sizeof(int32) }, + { &gbSgbMultiplayer, sizeof(int32) }, + { &gbSgbNextController, sizeof(u8) }, + { &gbSgbReadingController, sizeof(u8) }, + { NULL, 0 } +}; + +variable_desc gbSgbSaveStructV3[] = { + { &gbSgbMask, sizeof(int32) }, + { &gbSgbPacketState, sizeof(int32) }, + { &gbSgbBit, sizeof(int32) }, + { &gbSgbPacketNBits, sizeof(int32) }, + { &gbSgbPacketByte, sizeof(int32) }, + { &gbSgbPacketNumber, sizeof(int32) }, + { &gbSgbMultiplayer, sizeof(int32) }, + { &gbSgbNextController, sizeof(u8) }, + { &gbSgbReadingController, sizeof(u8) }, + { &gbSgbFourPlayers, sizeof(int32) }, + { NULL, 0 } +}; + +void gbSgbSaveGame(gzFile gzFile) +{ + utilWriteData(gzFile, gbSgbSaveStructV3); + + utilGzWrite(gzFile, gbSgbBorder, 2048); + utilGzWrite(gzFile, gbSgbBorderChar, 32 * 256); + + utilGzWrite(gzFile, gbSgbPacket, 16 * 7); + + utilGzWrite(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); + utilGzWrite(gzFile, gbSgbATF, 20 * 18); + utilGzWrite(gzFile, gbSgbATFList, 45 * 20 * 18); + + utilGzWrite(gzFile, gbSgbScreenBuffer, 4160); + utilGzWrite(gzFile, &gbSgbMode, sizeof(gbSgbMode)); + utilGzWrite(gzFile, &gbSgbCGBSupport, sizeof(gbSgbCGBSupport)); + utilGzWrite(gzFile, &gbSgbPacketTimeout, sizeof(gbSgbPacketTimeout)); +} + +void gbSgbReadGame(gzFile gzFile, int version) +{ + if (version >= 3) + utilReadData(gzFile, gbSgbSaveStructV3); + else + { + utilReadData(gzFile, gbSgbSaveStruct); + gbSgbFourPlayers = 0; + } + + if (version >= 8) + { + utilGzRead(gzFile, gbSgbBorder, 2048); + utilGzRead(gzFile, gbSgbBorderChar, 32 * 256); + } + + utilGzRead(gzFile, gbSgbPacket, 16 * 7); + + utilGzRead(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); + utilGzRead(gzFile, gbSgbATF, 20 * 18); + utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18); + + if (version >= 11) + { + utilGzRead(gzFile, gbSgbScreenBuffer, 4160); + utilGzRead(gzFile, &gbSgbMode, sizeof(gbSgbMode)); + utilGzRead(gzFile, &gbSgbCGBSupport, sizeof(gbSgbCGBSupport)); + utilGzRead(gzFile, &gbSgbPacketTimeout, sizeof(gbSgbPacketTimeout)); + } +} + diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbSGB.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbSGB.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,30 @@ +#ifndef VBA_GB_SGB_H +#define VBA_GB_SGB_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "zlib.h" +#include "../Port.h" + +void gbSgbInit(); +void gbSgbShutdown(); +void gbSgbCommand(); +void gbSgbResetPacketState(); +void gbSgbReset(); +void gbSgbDoBitTransfer(u8); +void gbSgbSaveGame(gzFile); +void gbSgbReadGame(gzFile, int version); +void gbSgbRenderBorder(); + +extern u8 gbSgbATF[20*18]; +extern int32 gbSgbMode; +extern int32 gbSgbMask; +extern int32 gbSgbMultiplayer; +extern u8 gbSgbNextController; +extern int32 gbSgbPacketTimeout; +extern u8 gbSgbReadingController; +extern int32 gbSgbFourPlayers; + +#endif // VBA_GB_SGB_H diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbSound.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbSound.cpp Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,1139 @@ +#ifdef WIN32 +# include "../win32/stdafx.h" +# include "../win32/VBA.h" +#endif + +#include +#include + +#include "../common/System.h" +#include "../common/Util.h" +//#include "../Blip_Buffer.h" +#include "gbGlobals.h" +#include "gbSound.h" + +#ifndef countof +#define countof(a) (sizeof(a) / sizeof(a[0])) +#endif + +extern u8 soundBuffer[6][735]; +extern u16 soundFinalWave[1470]; +extern u16 soundFrameSound[735 * 30 * 2]; +extern int32 soundVolume; + +soundtick_t GB_USE_TICKS_AS = 24; // (1048576.0/44100.0); // FIXME: (4194304.0/70224.0)(fps) vs 60.0fps? + +#define SOUND_MAGIC 0x60000000 +#define SOUND_MAGIC_2 0x30000000 +#define NOISE_MAGIC (2097152.0 / 44100.0) + +extern int32 speed; + +extern u8 soundWavePattern[4][32]; + +extern u32 soundBufferLen; +extern u32 soundBufferTotalLen; +extern int32 soundQuality; +extern int32 soundPaused; +extern int32 soundPlay; +extern soundtick_t soundTicks; +extern soundtick_t SOUND_CLOCK_TICKS; +extern u32 soundNextPosition; + +extern int32 soundLevel1; +extern int32 soundLevel2; +extern int32 soundBalance; +extern int32 soundMasterOn; +extern u32 soundIndex; +extern u32 soundBufferIndex; +extern int32 soundFrameSoundWritten; +int32 soundVIN = 0; +extern int32 soundDebug; + +extern int32 sound1On; +extern int32 sound1ATL; +extern int32 sound1Skip; +extern int32 sound1Index; +extern int32 sound1Continue; +extern int32 sound1EnvelopeVolume; +extern int32 sound1EnvelopeATL; +extern int32 sound1EnvelopeUpDown; +extern int32 sound1EnvelopeATLReload; +extern int32 sound1SweepATL; +extern int32 sound1SweepATLReload; +extern int32 sound1SweepSteps; +extern int32 sound1SweepUpDown; +extern int32 sound1SweepStep; +extern u8 * sound1Wave; + +extern int32 sound2On; +extern int32 sound2ATL; +extern int32 sound2Skip; +extern int32 sound2Index; +extern int32 sound2Continue; +extern int32 sound2EnvelopeVolume; +extern int32 sound2EnvelopeATL; +extern int32 sound2EnvelopeUpDown; +extern int32 sound2EnvelopeATLReload; +extern u8 * sound2Wave; + +extern int32 sound3On; +extern int32 sound3ATL; +extern int32 sound3Skip; +extern int32 sound3Index; +extern int32 sound3Continue; +extern int32 sound3OutputLevel; +extern int32 sound3Last; + +extern int32 sound4On; +extern int32 sound4Clock; +extern int32 sound4ATL; +extern int32 sound4Skip; +extern int32 sound4Index; +extern int32 sound4ShiftRight; +extern int32 sound4ShiftSkip; +extern int32 sound4ShiftIndex; +extern int32 sound4NSteps; +extern int32 sound4CountDown; +extern int32 sound4Continue; +extern int32 sound4EnvelopeVolume; +extern int32 sound4EnvelopeATL; +extern int32 sound4EnvelopeUpDown; +extern int32 sound4EnvelopeATLReload; + +extern int32 soundEnableFlag; +extern int32 soundMutedFlag; + +extern int32 soundFreqRatio[8]; +extern int32 soundShiftClock[16]; + +extern s16 soundFilter[4000]; +extern s16 soundLeft[5]; +extern s16 soundRight[5]; +extern int32 soundEchoIndex; +extern bool8 soundEcho; +extern bool8 soundLowPass; +extern bool8 soundReverse; +extern bool8 soundOffFlag; + +bool8 gbDigitalSound = false; + +void gbSoundEvent(register u16 address, register int data) +{ + int freq = 0; + + gbMemory[address] = data; + +#ifndef FINAL_VERSION + if (soundDebug) + { + // don't translate. debug only + log("Sound event: %08lx %02x\n", address, data); + } +#endif + switch (address) + { + case NR10: + sound1SweepATL = sound1SweepATLReload = 344 * ((data >> 4) & 7); + sound1SweepSteps = data & 7; + sound1SweepUpDown = data & 0x08; + sound1SweepStep = 0; + break; + case NR11: + sound1Wave = soundWavePattern[data >> 6]; + sound1ATL = 172 * (64 - (data & 0x3f)); + break; + case NR12: + sound1EnvelopeVolume = data >> 4; + sound1EnvelopeUpDown = data & 0x08; + sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (data & 7); + break; + case NR13: + freq = (((int)(gbMemory[NR14] & 7)) << 8) | data; + sound1ATL = 172 * (64 - (gbMemory[NR11] & 0x3f)); + freq = 2048 - freq; + if (freq) + { + sound1Skip = SOUND_MAGIC / freq; + } + else + sound1Skip = 0; + break; + case NR14: + freq = (((int)(data & 7) << 8) | gbMemory[NR13]); + freq = 2048 - freq; + sound1ATL = 172 * (64 - (gbMemory[NR11] & 0x3f)); + sound1Continue = data & 0x40; + if (freq) + { + sound1Skip = SOUND_MAGIC / freq; + } + else + sound1Skip = 0; + if (data & 0x80) + { + gbMemory[NR52] |= 1; + sound1EnvelopeVolume = gbMemory[NR12] >> 4; + sound1EnvelopeUpDown = gbMemory[NR12] & 0x08; + sound1ATL = 172 * (64 - (gbMemory[NR11] & 0x3f)); + sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (gbMemory[NR12] & 7); + sound1SweepATL = sound1SweepATLReload = 344 * ((gbMemory[NR10] >> 4) & 7); + sound1SweepSteps = gbMemory[NR10] & 7; + sound1SweepUpDown = gbMemory[NR10] & 0x08; + sound1SweepStep = 0; + + sound1Index = 0; + sound1On = 1; + } + break; + case NR21: + sound2Wave = soundWavePattern[data >> 6]; + sound2ATL = 172 * (64 - (data & 0x3f)); + break; + case NR22: + sound2EnvelopeVolume = data >> 4; + sound2EnvelopeUpDown = data & 0x08; + sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (data & 7); + break; + case NR23: + freq = (((int)(gbMemory[NR24] & 7)) << 8) | data; + sound2ATL = 172 * (64 - (gbMemory[NR21] & 0x3f)); + freq = 2048 - freq; + if (freq) + { + sound2Skip = SOUND_MAGIC / freq; + } + else + sound2Skip = 0; + break; + case NR24: + freq = (((int)(data & 7) << 8) | gbMemory[NR23]); + freq = 2048 - freq; + sound2ATL = 172 * (64 - (gbMemory[NR21] & 0x3f)); + sound2Continue = data & 0x40; + if (freq) + { + sound2Skip = SOUND_MAGIC / freq; + } + else + sound2Skip = 0; + if (data & 0x80) + { + gbMemory[NR52] |= 2; + sound2EnvelopeVolume = gbMemory[NR22] >> 4; + sound2EnvelopeUpDown = gbMemory[NR22] & 0x08; + sound2ATL = 172 * (64 - (gbMemory[NR21] & 0x3f)); + sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (gbMemory[NR22] & 7); + + sound2Index = 0; + sound2On = 1; + } + break; + case NR30: + if (!(data & 0x80)) + { + gbMemory[NR52] &= 0xfb; + sound3On = 0; + } + break; + case NR31: + sound3ATL = 172 * (256 - data); + break; + case NR32: + sound3OutputLevel = (data >> 5) & 3; + break; + case NR33: + freq = 2048 - (((int)(gbMemory[NR34] & 7) << 8) | data); + if (freq) + { + sound3Skip = SOUND_MAGIC_2 / freq; + } + else + sound3Skip = 0; + break; + case NR34: + freq = 2048 - (((data & 7) << 8) | (int)gbMemory[NR33]); + if (freq) + { + sound3Skip = SOUND_MAGIC_2 / freq; + } + else + { + sound3Skip = 0; + } + sound3Continue = data & 0x40; + if ((data & 0x80) && (gbMemory[NR30] & 0x80)) + { + gbMemory[NR52] |= 4; + sound3ATL = 172 * (256 - gbMemory[NR31]); + sound3Index = 0; + sound3On = 1; + } + break; + case NR41: + sound4ATL = 172 * (64 - (data & 0x3f)); + break; + case NR42: + sound4EnvelopeVolume = data >> 4; + sound4EnvelopeUpDown = data & 0x08; + sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (data & 7); + break; + case NR43: + freq = soundFreqRatio[data & 7]; + sound4NSteps = data & 0x08; + + sound4Skip = freq * NOISE_MAGIC; + + sound4Clock = data >> 4; + + freq = freq / soundShiftClock[sound4Clock]; + + sound4ShiftSkip = freq * NOISE_MAGIC; + + break; + case NR44: + sound4Continue = data & 0x40; + if (data & 0x80) + { + gbMemory[NR52] |= 8; + sound4EnvelopeVolume = gbMemory[NR42] >> 4; + sound4EnvelopeUpDown = gbMemory[NR42] & 0x08; + sound4ATL = 172 * (64 - (gbMemory[NR41] & 0x3f)); + sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (gbMemory[NR42] & 7); + + sound4On = 1; + + sound4Index = 0; + sound4ShiftIndex = 0; + + freq = soundFreqRatio[gbMemory[NR43] & 7]; + + sound4Skip = freq * NOISE_MAGIC; + + sound4NSteps = gbMemory[NR43] & 0x08; + + freq = freq / soundShiftClock[gbMemory[NR43] >> 4]; + + sound4ShiftSkip = freq * NOISE_MAGIC; + if (sound4NSteps) + sound4ShiftRight = 0x7f; + else + sound4ShiftRight = 0x7fff; + } + break; + case NR50: + soundVIN = data & 0x88; + soundLevel1 = data & 7; + soundLevel2 = (data >> 4) & 7; + break; + case NR51: + soundBalance = (data & soundEnableFlag); + gbMemory[address] = data; + break; + case NR52: + soundMasterOn = data & 0x80; + if (!(data & 0x80)) + { + sound1On = 0; + sound2On = 0; + sound3On = 0; + sound4On = 0; + } + break; + } + + gbDigitalSound = true; + + if (sound1On && sound1EnvelopeVolume != 0) + gbDigitalSound = false; + if (sound2On && sound2EnvelopeVolume != 0) + gbDigitalSound = false; + if (sound3On && sound3OutputLevel != 0) + gbDigitalSound = false; + if (sound4On && sound4EnvelopeVolume != 0) + gbDigitalSound = false; +} + +void gbSoundChannel1() +{ + int vol = sound1EnvelopeVolume; + + int freq = 0; + + int value = 0; + + if (sound1On && (sound1ATL || !sound1Continue)) + { + sound1Index += soundQuality * sound1Skip; + sound1Index &= 0x1fffffff; + + value = ((s8)sound1Wave[sound1Index >> 24]) * vol; + } + + soundBuffer[0][soundIndex] = value; + + if (sound1On) + { + if (sound1ATL) + { + sound1ATL -= soundQuality; + + if (sound1ATL <= 0 && sound1Continue) + { + gbMemory[NR52] &= 0xfe; + sound1On = 0; + } + } + + if (sound1EnvelopeATL) + { + sound1EnvelopeATL -= soundQuality; + + if (sound1EnvelopeATL <= 0) + { + if (sound1EnvelopeUpDown) + { + if (sound1EnvelopeVolume < 15) + sound1EnvelopeVolume++; + } + else + { + if (sound1EnvelopeVolume) + sound1EnvelopeVolume--; + } + + sound1EnvelopeATL += sound1EnvelopeATLReload; + } + } + + if (sound1SweepATL) + { + sound1SweepATL -= soundQuality; + + if (sound1SweepATL <= 0) + { + freq = (((int)(gbMemory[NR14] & 7) << 8) | gbMemory[NR13]); + + int updown = 1; + + if (sound1SweepUpDown) + updown = -1; + + int newfreq = 0; + if (sound1SweepSteps) + { + newfreq = freq + updown * freq / (1 << sound1SweepSteps); + if (newfreq == freq) + newfreq = 0; + } + else + newfreq = freq; + + if (newfreq < 0) + { + sound1SweepATL += sound1SweepATLReload; + } + else if (newfreq > 2047) + { + sound1SweepATL = 0; + sound1On = 0; + gbMemory[NR52] &= 0xfe; + } + else + { + sound1SweepATL += sound1SweepATLReload; + sound1Skip = SOUND_MAGIC / (2048 - newfreq); + + gbMemory[NR13] = newfreq & 0xff; + gbMemory[NR14] = (gbMemory[NR14] & 0xf8) | ((newfreq >> 8) & 7); + } + } + } + } +} + +void gbSoundChannel2() +{ + // int freq = 0; + int vol = sound2EnvelopeVolume; + + int value = 0; + + if (sound2On && (sound2ATL || !sound2Continue)) + { + sound2Index += soundQuality * sound2Skip; + sound2Index &= 0x1fffffff; + + value = ((s8)sound2Wave[sound2Index >> 24]) * vol; + } + + soundBuffer[1][soundIndex] = value; + + if (sound2On) + { + if (sound2ATL) + { + sound2ATL -= soundQuality; + + if (sound2ATL <= 0 && sound2Continue) + { + gbMemory[NR52] &= 0xfd; + sound2On = 0; + } + } + + if (sound2EnvelopeATL) + { + sound2EnvelopeATL -= soundQuality; + + if (sound2EnvelopeATL <= 0) + { + if (sound2EnvelopeUpDown) + { + if (sound2EnvelopeVolume < 15) + sound2EnvelopeVolume++; + } + else + { + if (sound2EnvelopeVolume) + sound2EnvelopeVolume--; + } + sound2EnvelopeATL += sound2EnvelopeATLReload; + } + } + } +} + +void gbSoundChannel3() +{ + int value = sound3Last; + + if (sound3On && (sound3ATL || !sound3Continue)) + { + sound3Index += soundQuality * sound3Skip; + sound3Index &= 0x1fffffff; + + value = gbMemory[0xff30 + (sound3Index >> 25)]; + + if ((sound3Index & 0x01000000)) + { + value &= 0x0f; + } + else + { + value >>= 4; + } + + value -= 8; + value *= 2; + + switch (sound3OutputLevel) + { + case 0: + value = 0; + break; + case 1: + break; + case 2: + value = (value >> 1); + break; + case 3: + value = (value >> 2); + break; + } + //value += 1; + sound3Last = value; + } + + soundBuffer[2][soundIndex] = value; + + if (sound3On) + { + if (sound3ATL) + { + sound3ATL -= soundQuality; + + if (sound3ATL <= 0 && sound3Continue) + { + gbMemory[NR52] &= 0xfb; + sound3On = 0; + } + } + } +} + +void gbSoundChannel4() +{ + int vol = sound4EnvelopeVolume; + + int value = 0; + + if (sound4Clock <= 0x0c) + { + if (sound4On && (sound4ATL || !sound4Continue)) + { + #define NOISE_ONE_SAMP_SCALE 0x200000 + + sound4Index += soundQuality * sound4Skip; + sound4ShiftIndex += soundQuality * sound4ShiftSkip; + + if (sound4NSteps) + { + while (sound4ShiftIndex >= NOISE_ONE_SAMP_SCALE) + { + sound4ShiftRight = (((sound4ShiftRight << 6) ^ + (sound4ShiftRight << 5)) & 0x40) | + (sound4ShiftRight >> 1); + sound4ShiftIndex -= NOISE_ONE_SAMP_SCALE; + } + } + else + { + while (sound4ShiftIndex >= NOISE_ONE_SAMP_SCALE) + { + sound4ShiftRight = (((sound4ShiftRight << 14) ^ + (sound4ShiftRight << 13)) & 0x4000) | + (sound4ShiftRight >> 1); + + sound4ShiftIndex -= NOISE_ONE_SAMP_SCALE; + } + } + + sound4Index %= NOISE_ONE_SAMP_SCALE; + sound4ShiftIndex %= NOISE_ONE_SAMP_SCALE; + + value = ((sound4ShiftRight & 1) * 2 - 1) * vol; + } + else + { + value = 0; + } + } + + soundBuffer[3][soundIndex] = value; + + if (sound4On) + { + if (sound4ATL) + { + sound4ATL -= soundQuality; + + if (sound4ATL <= 0 && sound4Continue) + { + gbMemory[NR52] &= 0xfd; + sound4On = 0; + } + } + + if (sound4EnvelopeATL) + { + sound4EnvelopeATL -= soundQuality; + + if (sound4EnvelopeATL <= 0) + { + if (sound4EnvelopeUpDown) + { + if (sound4EnvelopeVolume < 15) + sound4EnvelopeVolume++; + } + else + { + if (sound4EnvelopeVolume) + sound4EnvelopeVolume--; + } + sound4EnvelopeATL += sound4EnvelopeATLReload; + } + } + } +} + +void gbSoundMix() +{ + int res = 0; + + if (gbMemory) + soundBalance = (gbMemory[NR51] & soundEnableFlag & ~soundMutedFlag); + + if (soundBalance & 16) + { + res += ((s8)soundBuffer[0][soundIndex]); + } + if (soundBalance & 32) + { + res += ((s8)soundBuffer[1][soundIndex]); + } + if (soundBalance & 64) + { + res += ((s8)soundBuffer[2][soundIndex]); + } + if (soundBalance & 128) + { + res += ((s8)soundBuffer[3][soundIndex]); + } + + if (gbDigitalSound) + res = soundLevel1 * 256; + else + res *= soundLevel1 * 60; + + if (soundEcho) + { + res *= 2; + res += soundFilter[soundEchoIndex]; + res /= 2; + soundFilter[soundEchoIndex++] = res; + } + + if (soundLowPass) + { + soundLeft[4] = soundLeft[3]; + soundLeft[3] = soundLeft[2]; + soundLeft[2] = soundLeft[1]; + soundLeft[1] = soundLeft[0]; + soundLeft[0] = res; + res = (soundLeft[4] + 2 * soundLeft[3] + 8 * soundLeft[2] + 2 * soundLeft[1] + + soundLeft[0]) / 14; + } + + bool noSpecialEffects = false; +#if (defined(WIN32) && !defined(SDL)) + if (theApp.soundRecording || theApp.aviRecording || theApp.nvAudioLog) + noSpecialEffects = true; +#endif + + if (!noSpecialEffects) + { + switch (soundVolume) + { + case 0: + case 1: + case 2: + case 3: + res *= (soundVolume + 1); + break; + case 4: + res >>= 2; + break; + case 5: + res >>= 1; + break; + } + } + + if (res > 32767) + res = 32767; + if (res < -32768) + res = -32768; + + if (soundReverse && !noSpecialEffects) + { + soundFinalWave[++soundBufferIndex] = res; + if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound)) + /*assert(false)*/; + else + soundFrameSound[++soundFrameSoundWritten] = res; + } + else + { + soundFinalWave[soundBufferIndex++] = res; + if (soundFrameSoundWritten >= countof(soundFrameSound)) + /*assert(false)*/; + else + soundFrameSound[soundFrameSoundWritten++] = res; + } + + res = 0; + + if (soundBalance & 1) + { + res += ((s8)soundBuffer[0][soundIndex]); + } + if (soundBalance & 2) + { + res += ((s8)soundBuffer[1][soundIndex]); + } + if (soundBalance & 4) + { + res += ((s8)soundBuffer[2][soundIndex]); + } + if (soundBalance & 8) + { + res += ((s8)soundBuffer[3][soundIndex]); + } + + if (gbDigitalSound) + res = soundLevel2 * 256; + else + res *= soundLevel2 * 60; + + if (soundEcho) + { + res *= 2; + res += soundFilter[soundEchoIndex]; + res /= 2; + soundFilter[soundEchoIndex++] = res; + + if (soundEchoIndex >= 4000) + soundEchoIndex = 0; + } + + if (soundLowPass) + { + soundRight[4] = soundRight[3]; + soundRight[3] = soundRight[2]; + soundRight[2] = soundRight[1]; + soundRight[1] = soundRight[0]; + soundRight[0] = res; + res = (soundRight[4] + 2 * soundRight[3] + 8 * soundRight[2] + 2 * soundRight[1] + + soundRight[0]) / 14; + } + + if (!noSpecialEffects) + { + switch (soundVolume) + { + case 0: + case 1: + case 2: + case 3: + res *= (soundVolume + 1); + break; + case 4: + res >>= 2; + break; + case 5: + res >>= 1; + break; + } + } + + if (res > 32767) + res = 32767; + if (res < -32768) + res = -32768; + + if (soundReverse && !noSpecialEffects) + { + soundFinalWave[-1 + soundBufferIndex++] = res; + if ((soundFrameSoundWritten) >= countof(soundFrameSound)) + /*assert(false)*/; + else + soundFrameSound[-1 + soundFrameSoundWritten++] = res; + } + else + { + soundFinalWave[soundBufferIndex++] = res; + if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound)) + /*assert(false)*/; + else + soundFrameSound[soundFrameSoundWritten++] = res; + } +} + +void gbSoundTick() +{ + if (systemSoundOn) + { + if (soundMasterOn) + { + gbSoundChannel1(); + gbSoundChannel2(); + gbSoundChannel3(); + gbSoundChannel4(); + + gbSoundMix(); + } + else + { + soundFinalWave[soundBufferIndex++] = 0; + soundFinalWave[soundBufferIndex++] = 0; + if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound)) + /*assert(false)*/; + else + { + soundFrameSound[soundFrameSoundWritten++] = 0; + soundFrameSound[soundFrameSoundWritten++] = 0; + } + } + + soundIndex++; + + if (2 * soundBufferIndex >= soundBufferLen) + { + if (systemSoundOn) + { + if (soundPaused) + { + extern void soundResume(); + soundResume(); + } + + systemSoundWriteToBuffer(); + } + soundIndex = 0; + soundBufferIndex = 0; + } + } +} + +void gbSoundReset() +{ + soundPaused = 1; + soundPlay = 0; + SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS; +// soundTicks = SOUND_CLOCK_TICKS; + soundTicks = 0; + soundNextPosition = 0; + soundMasterOn = 1; + soundIndex = 0; + soundBufferIndex = 0; + soundLevel1 = 7; + soundLevel2 = 7; + soundVIN = 0; + + sound1On = 0; + sound1ATL = 0; + sound1Skip = 0; + sound1Index = 0; + sound1Continue = 0; + sound1EnvelopeVolume = 0; + sound1EnvelopeATL = 0; + sound1EnvelopeUpDown = 0; + sound1EnvelopeATLReload = 0; + sound1SweepATL = 0; + sound1SweepATLReload = 0; + sound1SweepSteps = 0; + sound1SweepUpDown = 0; + sound1SweepStep = 0; + sound1Wave = soundWavePattern[2]; + + sound2On = 0; + sound2ATL = 0; + sound2Skip = 0; + sound2Index = 0; + sound2Continue = 0; + sound2EnvelopeVolume = 0; + sound2EnvelopeATL = 0; + sound2EnvelopeUpDown = 0; + sound2EnvelopeATLReload = 0; + sound2Wave = soundWavePattern[2]; + + sound3On = 0; + sound3ATL = 0; + sound3Skip = 0; + sound3Index = 0; + sound3Continue = 0; + sound3OutputLevel = 0; + + sound4On = 0; + sound4Clock = 0; + sound4ATL = 0; + sound4Skip = 0; + sound4Index = 0; + sound4ShiftRight = 0x7f; + sound4NSteps = 0; + sound4CountDown = 0; + sound4Continue = 0; + sound4EnvelopeVolume = 0; + sound4EnvelopeATL = 0; + sound4EnvelopeUpDown = 0; + sound4EnvelopeATLReload = 0; + + // don't translate + if (soundDebug) + { + log("*** Sound Init ***\n"); + } + + gbSoundEvent(0xff10, 0x80); + gbSoundEvent(0xff11, 0xbf); + gbSoundEvent(0xff12, 0xf3); + gbSoundEvent(0xff14, 0xbf); + gbSoundEvent(0xff16, 0x3f); + gbSoundEvent(0xff17, 0x00); + gbSoundEvent(0xff19, 0xbf); + + gbSoundEvent(0xff1a, 0x7f); + gbSoundEvent(0xff1b, 0xff); + gbSoundEvent(0xff1c, 0xbf); + gbSoundEvent(0xff1e, 0xbf); + + gbSoundEvent(0xff20, 0xff); + gbSoundEvent(0xff21, 0x00); + gbSoundEvent(0xff22, 0x00); + gbSoundEvent(0xff23, 0xbf); + gbSoundEvent(0xff24, 0x77); + gbSoundEvent(0xff25, 0xf3); + + gbSoundEvent(0xff26, 0xf0); + + // don't translate + if (soundDebug) + { + log("*** Sound Init Complete ***\n"); + } + + sound1On = 0; + sound2On = 0; + sound3On = 0; + sound4On = 0; + + int addr = 0xff30; + + while (addr < 0xff40) + { + gbMemory[addr++] = 0x00; + gbMemory[addr++] = 0xff; + } + + memset(soundFinalWave, 0x00, soundBufferLen); + + memset(soundFilter, 0, sizeof(soundFilter)); + soundEchoIndex = 0; +} + +extern bool soundInit(); +extern void soundShutdown(); + +void gbSoundSetQuality(int quality) +{ + if (soundQuality != quality && systemSoundCanChangeQuality()) + { + if (!soundOffFlag) + soundShutdown(); + soundQuality = quality; + soundNextPosition = 0; + if (!soundOffFlag) + soundInit(); + SOUND_CLOCK_TICKS = (gbSpeed ? 2 : 1) * GB_USE_TICKS_AS * soundQuality; + soundIndex = 0; + soundBufferIndex = 0; + } + else + { + soundNextPosition = 0; + SOUND_CLOCK_TICKS = (gbSpeed ? 2 : 1) * GB_USE_TICKS_AS * soundQuality; + soundIndex = 0; + soundBufferIndex = 0; + } +} + +static int32 soundTicks_int32; +static int32 SOUND_CLOCK_TICKS_int32; +variable_desc gbSoundSaveStruct[] = { + { &soundPaused, sizeof(int32) }, + { &soundPlay, sizeof(int32) }, + { &soundTicks_int32, sizeof(int32) }, + { &SOUND_CLOCK_TICKS_int32, sizeof(int32) }, + { &soundLevel1, sizeof(int32) }, + { &soundLevel2, sizeof(int32) }, + { &soundBalance, sizeof(int32) }, + { &soundMasterOn, sizeof(int32) }, + { &soundIndex, sizeof(int32) }, + { &soundVIN, sizeof(int32) }, + { &sound1On, sizeof(int32) }, + { &sound1ATL, sizeof(int32) }, + { &sound1Skip, sizeof(int32) }, + { &sound1Index, sizeof(int32) }, + { &sound1Continue, sizeof(int32) }, + { &sound1EnvelopeVolume, sizeof(int32) }, + { &sound1EnvelopeATL, sizeof(int32) }, + { &sound1EnvelopeATLReload, sizeof(int32) }, + { &sound1EnvelopeUpDown, sizeof(int32) }, + { &sound1SweepATL, sizeof(int32) }, + { &sound1SweepATLReload, sizeof(int32) }, + { &sound1SweepSteps, sizeof(int32) }, + { &sound1SweepUpDown, sizeof(int32) }, + { &sound1SweepStep, sizeof(int32) }, + { &sound2On, sizeof(int32) }, + { &sound2ATL, sizeof(int32) }, + { &sound2Skip, sizeof(int32) }, + { &sound2Index, sizeof(int32) }, + { &sound2Continue, sizeof(int32) }, + { &sound2EnvelopeVolume, sizeof(int32) }, + { &sound2EnvelopeATL, sizeof(int32) }, + { &sound2EnvelopeATLReload, sizeof(int32) }, + { &sound2EnvelopeUpDown, sizeof(int32) }, + { &sound3On, sizeof(int32) }, + { &sound3ATL, sizeof(int32) }, + { &sound3Skip, sizeof(int32) }, + { &sound3Index, sizeof(int32) }, + { &sound3Continue, sizeof(int32) }, + { &sound3OutputLevel, sizeof(int32) }, + { &sound4On, sizeof(int32) }, + { &sound4ATL, sizeof(int32) }, + { &sound4Skip, sizeof(int32) }, + { &sound4Index, sizeof(int32) }, + { &sound4Clock, sizeof(int32) }, + { &sound4ShiftRight, sizeof(int32) }, + { &sound4ShiftSkip, sizeof(int32) }, + { &sound4ShiftIndex, sizeof(int32) }, + { &sound4NSteps, sizeof(int32) }, + { &sound4CountDown, sizeof(int32) }, + { &sound4Continue, sizeof(int32) }, + { &sound4EnvelopeVolume, sizeof(int32) }, + { &sound4EnvelopeATL, sizeof(int32) }, + { &sound4EnvelopeATLReload, sizeof(int32) }, + { &sound4EnvelopeUpDown, sizeof(int32) }, + { &soundEnableFlag, sizeof(int32) }, + { NULL, 0 } +}; + +//variable_desc gbSoundSaveStructV2[] = { +// { &soundTicks, sizeof(soundtick_t) }, +// { &SOUND_CLOCK_TICKS, sizeof(soundtick_t) }, +// { &GB_USE_TICKS_AS, sizeof(soundtick_t) }, +// { NULL, 0 } +//}; + +void gbSoundSaveGame(gzFile gzFile) +{ + soundTicks_int32 = (int32) soundTicks; + SOUND_CLOCK_TICKS_int32 = (int32) SOUND_CLOCK_TICKS; + + utilWriteData(gzFile, gbSoundSaveStruct); + + utilGzWrite(gzFile, soundBuffer, 4 * 735); + utilGzWrite(gzFile, soundFinalWave, 2 * 735); + utilGzWrite(gzFile, &soundQuality, sizeof(int32)); + + //utilWriteData(gzFile, gbSoundSaveStructV2); +} + +void gbSoundReadGame(int version, gzFile gzFile) +{ + int32 oldSoundPaused = soundPaused; + int32 oldSoundEnableFlag = soundEnableFlag; + utilReadData(gzFile, gbSoundSaveStruct); + soundPaused = oldSoundPaused; + soundEnableFlag = oldSoundEnableFlag; + + soundBufferIndex = soundIndex * 2; + + utilGzRead(gzFile, soundBuffer, 4 * 735); + utilGzRead(gzFile, soundFinalWave, 2 * 735); + + if (version >= 7) + { + int quality = 1; + utilGzRead(gzFile, &quality, sizeof(int32)); + gbSoundSetQuality(quality); + } + else + { + soundQuality = -1; + gbSoundSetQuality(1); + } + + sound1Wave = soundWavePattern[gbMemory[NR11] >> 6]; + sound2Wave = soundWavePattern[gbMemory[NR21] >> 6]; + + //if(version >= 14) { + // utilReadData(gzFile, gbSoundSaveStructV2); + //} + //else { + soundTicks = (soundtick_t) soundTicks_int32; + SOUND_CLOCK_TICKS = (soundtick_t) SOUND_CLOCK_TICKS_int32; + //} +} + diff -r 9e598342e182 -r 75e5bb1e0aa1 src/gb/gbSound.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gb/gbSound.h Sat Mar 03 11:44:47 2012 -0600 @@ -0,0 +1,51 @@ +#ifndef VBA_GB_SOUND_H +#define VBA_GB_SOUND_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define NR10 0xff10 +#define NR11 0xff11 +#define NR12 0xff12 +#define NR13 0xff13 +#define NR14 0xff14 +#define NR21 0xff16 +#define NR22 0xff17 +#define NR23 0xff18 +#define NR24 0xff19 +#define NR30 0xff1a +#define NR31 0xff1b +#define NR32 0xff1c +#define NR33 0xff1d +#define NR34 0xff1e +#define NR41 0xff20 +#define NR42 0xff21 +#define NR43 0xff22 +#define NR44 0xff23 +#define NR50 0xff24 +#define NR51 0xff25 +#define NR52 0xff26 + +#define SOUND_EVENT(address, value) \ + gbSoundEvent(address, value) + +extern void gbSoundTick(); +extern void gbSoundPause(); +extern void gbSoundResume(); +extern void gbSoundEnable(int); +extern void gbSoundDisable(int); +extern int gbSoundGetEnable(); +extern void gbSoundReset(); +extern void gbSoundSaveGame(gzFile); +extern void gbSoundReadGame(int, gzFile); +extern void gbSoundEvent(register u16, register int); +extern void gbSoundSetQuality(int); + +typedef int32 soundtick_t; + +extern soundtick_t soundTicks; +extern int32 soundQuality; +extern soundtick_t SOUND_CLOCK_TICKS; + +#endif // VBA_GB_SOUND_H