From 48086ba62fa383bb82eaa1a7518d202037de738f Mon Sep 17 00:00:00 2001 From: Zach Bacon Date: Sat, 9 Jul 2016 09:53:13 -0400 Subject: [PATCH] some more formating things etc --- src/gb/GB.cpp | 9573 ++++++++++++++++++++---------------------- src/gb/gb.h | 38 +- src/gb/gbCheats.cpp | 761 ++-- src/gb/gbCheats.h | 34 +- src/gb/gbCodes.h | 365 +- src/gb/gbCodesCB.h | 132 +- src/gb/gbDis.cpp | 384 +- src/gb/gbGfx.cpp | 997 +++-- src/gb/gbGlobals.cpp | 24 +- src/gb/gbGlobals.h | 18 +- src/gb/gbMemory.cpp | 2714 ++++++------ src/gb/gbMemory.h | 202 +- src/gb/gbPrinter.cpp | 265 +- src/gb/gbSGB.cpp | 1335 +++--- src/gb/gbSound.cpp | 617 +-- src/gb/gbSound.h | 12 +- 16 files changed, 8443 insertions(+), 9028 deletions(-) diff --git a/src/gb/GB.cpp b/src/gb/GB.cpp index 64bf1b69..c89029c5 100644 --- a/src/gb/GB.cpp +++ b/src/gb/GB.cpp @@ -1,27 +1,27 @@ //#include "../win32/stdafx.h" // would fix LNK2005 linker errors for MSVC +#include +#include #include #include #include -#include -#include -#include "../System.h" #include "../NLS.h" +#include "../System.h" +#include "../Util.h" +#include "../common/ConfigManager.h" +#include "../gba/GBALink.h" #include "gb.h" #include "gbCheats.h" #include "gbGlobals.h" #include "gbMemory.h" #include "gbSGB.h" #include "gbSound.h" -#include "../Util.h" -#include "../gba/GBALink.h" -#include "../common/ConfigManager.h" #ifdef __GNUC__ #define _stricmp strcasecmp #endif -extern uint8_t *pix; +extern uint8_t* pix; bool gbUpdateSizes(); bool inBios = false; @@ -32,8 +32,8 @@ char gbBuffer[2048]; extern uint16_t gbLineMix[160]; // mappers -void (*mapper)(uint16_t,uint8_t) = NULL; -void (*mapperRAM)(uint16_t,uint8_t) = NULL; +void (*mapper)(uint16_t, uint8_t) = NULL; +void (*mapperRAM)(uint16_t, uint8_t) = NULL; uint8_t (*mapperReadRAM)(uint16_t) = NULL; void (*mapperUpdateClock)() = NULL; @@ -46,35 +46,35 @@ gbRegister DE; gbRegister HL; uint16_t IFF = 0; // 0xff04 -uint8_t register_DIV = 0; +uint8_t register_DIV = 0; // 0xff05 -uint8_t register_TIMA = 0; +uint8_t register_TIMA = 0; // 0xff06 -uint8_t register_TMA = 0; +uint8_t register_TMA = 0; // 0xff07 -uint8_t register_TAC = 0; +uint8_t register_TAC = 0; // 0xff0f -uint8_t register_IF = 0; +uint8_t register_IF = 0; // 0xff40 -uint8_t register_LCDC = 0; +uint8_t register_LCDC = 0; // 0xff41 -uint8_t register_STAT = 0; +uint8_t register_STAT = 0; // 0xff42 -uint8_t register_SCY = 0; +uint8_t register_SCY = 0; // 0xff43 -uint8_t register_SCX = 0; +uint8_t register_SCX = 0; // 0xff44 -uint8_t register_LY = 0; +uint8_t register_LY = 0; // 0xff45 -uint8_t register_LYC = 0; +uint8_t register_LYC = 0; // 0xff46 -uint8_t register_DMA = 0; +uint8_t register_DMA = 0; // 0xff4a -uint8_t register_WY = 0; +uint8_t register_WY = 0; // 0xff4b -uint8_t register_WX = 0; +uint8_t register_WX = 0; // 0xff4f -uint8_t register_VBK = 0; +uint8_t register_VBK = 0; // 0xff51 uint8_t register_HDMA1 = 0; // 0xff52 @@ -86,23 +86,23 @@ uint8_t register_HDMA4 = 0; // 0xff55 uint8_t register_HDMA5 = 0; // 0xff70 -uint8_t register_SVBK = 0; +uint8_t register_SVBK = 0; // 0xffff -uint8_t register_IE = 0; +uint8_t register_IE = 0; // ticks definition -int GBDIV_CLOCK_TICKS = 64; -int GBLCD_MODE_0_CLOCK_TICKS = 51; -int GBLCD_MODE_1_CLOCK_TICKS = 1140; -int GBLCD_MODE_2_CLOCK_TICKS = 20; -int GBLCD_MODE_3_CLOCK_TICKS = 43; +int GBDIV_CLOCK_TICKS = 64; +int GBLCD_MODE_0_CLOCK_TICKS = 51; +int GBLCD_MODE_1_CLOCK_TICKS = 1140; +int GBLCD_MODE_2_CLOCK_TICKS = 20; +int GBLCD_MODE_3_CLOCK_TICKS = 43; int GBLY_INCREMENT_CLOCK_TICKS = 114; int GBTIMER_MODE_0_CLOCK_TICKS = 256; int GBTIMER_MODE_1_CLOCK_TICKS = 4; int GBTIMER_MODE_2_CLOCK_TICKS = 16; int GBTIMER_MODE_3_CLOCK_TICKS = 64; -int GBSERIAL_CLOCK_TICKS = 128; -int GBSYNCHRONIZE_CLOCK_TICKS = 52920; +int GBSERIAL_CLOCK_TICKS = 128; +int GBSYNCHRONIZE_CLOCK_TICKS = 52920; // state variables @@ -136,15 +136,15 @@ bool gbIncreased = false; // not reset by writing to register_TIMA/TMA, but by // writing to register_DIV... int gbInternalTimer = 0x55; -const uint8_t gbTimerMask [4] = {0xff, 0x3, 0xf, 0x3f}; -const uint8_t gbTimerBug [8] = {0x80, 0x80, 0x02, 0x02, 0x0, 0xff, 0x0, 0xff}; +const uint8_t gbTimerMask[4] = { 0xff, 0x3, 0xf, 0x3f }; +const uint8_t gbTimerBug[8] = { 0x80, 0x80, 0x02, 0x02, 0x0, 0xff, 0x0, 0xff }; bool gbTimerModeChange = false; bool gbTimerOnChange = false; // lcd bool gbScreenOn = true; int gbLcdMode = 2; int gbLcdModeDelayed = 2; -int gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS-1; +int gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS - 1; int gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS; int gbLcdLYIncrementTicks = 114; int gbLcdLYIncrementTicksDelayed = 115; @@ -152,9 +152,9 @@ int gbScreenTicks = 0; uint8_t gbSCYLine[300]; uint8_t gbSCXLine[300]; uint8_t gbBgpLine[300]; -uint8_t gbObp0Line [300]; -uint8_t gbObp1Line [300]; -uint8_t gbSpritesTicks [300]; +uint8_t gbObp0Line[300]; +uint8_t gbObp1Line[300]; +uint8_t gbSpritesTicks[300]; uint8_t oldRegister_WY; bool gbLYChangeHappened = false; bool gbLCDChangeHappened = false; @@ -201,568 +201,565 @@ int gbJoymask[4] = { 0, 0, 0, 0 }; uint8_t gbRamFill = 0xff; -int gbRomSizes[] = { 0x00008000, // 32K - 0x00010000, // 64K - 0x00020000, // 128K - 0x00040000, // 256K - 0x00080000, // 512K - 0x00100000, // 1024K - 0x00200000, // 2048K - 0x00400000, // 4096K - 0x00800000 // 8192K +int gbRomSizes[] = { + 0x00008000, // 32K + 0x00010000, // 64K + 0x00020000, // 128K + 0x00040000, // 256K + 0x00080000, // 512K + 0x00100000, // 1024K + 0x00200000, // 2048K + 0x00400000, // 4096K + 0x00800000 // 8192K }; int gbRomSizesMasks[] = { 0x00007fff, - 0x0000ffff, - 0x0001ffff, - 0x0003ffff, - 0x0007ffff, - 0x000fffff, - 0x001fffff, - 0x003fffff, - 0x007fffff -}; + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff }; -int gbRamSizes[6] = { 0x00000000, // 0K - 0x00002000, // 2K // Changed to 2000 to avoid problems with gbMemoryMap... - 0x00002000, // 8K - 0x00008000, // 32K - 0x00020000, // 128K - 0x00010000 // 64K +int gbRamSizes[6] = { + 0x00000000, // 0K + 0x00002000, // 2K // Changed to 2000 to avoid problems with gbMemoryMap... + 0x00002000, // 8K + 0x00008000, // 32K + 0x00020000, // 128K + 0x00010000 // 64K }; int gbRamSizesMasks[6] = { 0x00000000, - 0x000007ff, - 0x00001fff, - 0x00007fff, - 0x0001ffff, - 0x0000ffff -}; + 0x000007ff, + 0x00001fff, + 0x00007fff, + 0x0001ffff, + 0x0000ffff }; int 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, 1, 3, 4, 2, 4, 2, 4, 3, 1, 3, 1, 2, 4, // d - 3, 3, 2, 1, 1, 4, 2, 4, 4, 1, 4, 1, 1, 1, 2, 4, // e - 3, 3, 2, 1, 1, 4, 2, 4, 3, 2, 4, 1, 0, 1, 2, 4 // f + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 + 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1 + 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2 + 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6 + 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b + 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c + 2, 3, 3, 1, 3, 4, 2, 4, 2, 4, 3, 1, 3, 1, 2, 4, // d + 3, 3, 2, 1, 1, 4, 2, 4, 4, 1, 4, 1, 1, 1, 2, 4, // e + 3, 3, 2, 1, 1, 4, 2, 4, 3, 2, 4, 1, 0, 1, 2, 4 // f }; int 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, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 8 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 9 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // a - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // b - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // c - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // d - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // e - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 // f + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 8 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 9 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // a + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // b + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // c + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // d + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // e + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 // f }; uint16_t DAATable[] = { - 0x0080,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, - 0x0800,0x0900,0x1000,0x1100,0x1200,0x1300,0x1400,0x1500, - 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, - 0x1800,0x1900,0x2000,0x2100,0x2200,0x2300,0x2400,0x2500, - 0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, - 0x2800,0x2900,0x3000,0x3100,0x3200,0x3300,0x3400,0x3500, - 0x3000,0x3100,0x3200,0x3300,0x3400,0x3500,0x3600,0x3700, - 0x3800,0x3900,0x4000,0x4100,0x4200,0x4300,0x4400,0x4500, - 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, - 0x4800,0x4900,0x5000,0x5100,0x5200,0x5300,0x5400,0x5500, - 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, - 0x5800,0x5900,0x6000,0x6100,0x6200,0x6300,0x6400,0x6500, - 0x6000,0x6100,0x6200,0x6300,0x6400,0x6500,0x6600,0x6700, - 0x6800,0x6900,0x7000,0x7100,0x7200,0x7300,0x7400,0x7500, - 0x7000,0x7100,0x7200,0x7300,0x7400,0x7500,0x7600,0x7700, - 0x7800,0x7900,0x8000,0x8100,0x8200,0x8300,0x8400,0x8500, - 0x8000,0x8100,0x8200,0x8300,0x8400,0x8500,0x8600,0x8700, - 0x8800,0x8900,0x9000,0x9100,0x9200,0x9300,0x9400,0x9500, - 0x9000,0x9100,0x9200,0x9300,0x9400,0x9500,0x9600,0x9700, - 0x9800,0x9900,0x0090,0x0110,0x0210,0x0310,0x0410,0x0510, - 0x0090,0x0110,0x0210,0x0310,0x0410,0x0510,0x0610,0x0710, - 0x0810,0x0910,0x1010,0x1110,0x1210,0x1310,0x1410,0x1510, - 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, - 0x1810,0x1910,0x2010,0x2110,0x2210,0x2310,0x2410,0x2510, - 0x2010,0x2110,0x2210,0x2310,0x2410,0x2510,0x2610,0x2710, - 0x2810,0x2910,0x3010,0x3110,0x3210,0x3310,0x3410,0x3510, - 0x3010,0x3110,0x3210,0x3310,0x3410,0x3510,0x3610,0x3710, - 0x3810,0x3910,0x4010,0x4110,0x4210,0x4310,0x4410,0x4510, - 0x4010,0x4110,0x4210,0x4310,0x4410,0x4510,0x4610,0x4710, - 0x4810,0x4910,0x5010,0x5110,0x5210,0x5310,0x5410,0x5510, - 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, - 0x5810,0x5910,0x6010,0x6110,0x6210,0x6310,0x6410,0x6510, - 0x6010,0x6110,0x6210,0x6310,0x6410,0x6510,0x6610,0x6710, - 0x6810,0x6910,0x7010,0x7110,0x7210,0x7310,0x7410,0x7510, - 0x7010,0x7110,0x7210,0x7310,0x7410,0x7510,0x7610,0x7710, - 0x7810,0x7910,0x8010,0x8110,0x8210,0x8310,0x8410,0x8510, - 0x8010,0x8110,0x8210,0x8310,0x8410,0x8510,0x8610,0x8710, - 0x8810,0x8910,0x9010,0x9110,0x9210,0x9310,0x9410,0x9510, - 0x9010,0x9110,0x9210,0x9310,0x9410,0x9510,0x9610,0x9710, - 0x9810,0x9910,0xA010,0xA110,0xA210,0xA310,0xA410,0xA510, - 0xA010,0xA110,0xA210,0xA310,0xA410,0xA510,0xA610,0xA710, - 0xA810,0xA910,0xB010,0xB110,0xB210,0xB310,0xB410,0xB510, - 0xB010,0xB110,0xB210,0xB310,0xB410,0xB510,0xB610,0xB710, - 0xB810,0xB910,0xC010,0xC110,0xC210,0xC310,0xC410,0xC510, - 0xC010,0xC110,0xC210,0xC310,0xC410,0xC510,0xC610,0xC710, - 0xC810,0xC910,0xD010,0xD110,0xD210,0xD310,0xD410,0xD510, - 0xD010,0xD110,0xD210,0xD310,0xD410,0xD510,0xD610,0xD710, - 0xD810,0xD910,0xE010,0xE110,0xE210,0xE310,0xE410,0xE510, - 0xE010,0xE110,0xE210,0xE310,0xE410,0xE510,0xE610,0xE710, - 0xE810,0xE910,0xF010,0xF110,0xF210,0xF310,0xF410,0xF510, - 0xF010,0xF110,0xF210,0xF310,0xF410,0xF510,0xF610,0xF710, - 0xF810,0xF910,0x0090,0x0110,0x0210,0x0310,0x0410,0x0510, - 0x0090,0x0110,0x0210,0x0310,0x0410,0x0510,0x0610,0x0710, - 0x0810,0x0910,0x1010,0x1110,0x1210,0x1310,0x1410,0x1510, - 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, - 0x1810,0x1910,0x2010,0x2110,0x2210,0x2310,0x2410,0x2510, - 0x2010,0x2110,0x2210,0x2310,0x2410,0x2510,0x2610,0x2710, - 0x2810,0x2910,0x3010,0x3110,0x3210,0x3310,0x3410,0x3510, - 0x3010,0x3110,0x3210,0x3310,0x3410,0x3510,0x3610,0x3710, - 0x3810,0x3910,0x4010,0x4110,0x4210,0x4310,0x4410,0x4510, - 0x4010,0x4110,0x4210,0x4310,0x4410,0x4510,0x4610,0x4710, - 0x4810,0x4910,0x5010,0x5110,0x5210,0x5310,0x5410,0x5510, - 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, - 0x5810,0x5910,0x6010,0x6110,0x6210,0x6310,0x6410,0x6510, - 0x0600,0x0700,0x0800,0x0900,0x0A00,0x0B00,0x0C00,0x0D00, - 0x0E00,0x0F00,0x1000,0x1100,0x1200,0x1300,0x1400,0x1500, - 0x1600,0x1700,0x1800,0x1900,0x1A00,0x1B00,0x1C00,0x1D00, - 0x1E00,0x1F00,0x2000,0x2100,0x2200,0x2300,0x2400,0x2500, - 0x2600,0x2700,0x2800,0x2900,0x2A00,0x2B00,0x2C00,0x2D00, - 0x2E00,0x2F00,0x3000,0x3100,0x3200,0x3300,0x3400,0x3500, - 0x3600,0x3700,0x3800,0x3900,0x3A00,0x3B00,0x3C00,0x3D00, - 0x3E00,0x3F00,0x4000,0x4100,0x4200,0x4300,0x4400,0x4500, - 0x4600,0x4700,0x4800,0x4900,0x4A00,0x4B00,0x4C00,0x4D00, - 0x4E00,0x4F00,0x5000,0x5100,0x5200,0x5300,0x5400,0x5500, - 0x5600,0x5700,0x5800,0x5900,0x5A00,0x5B00,0x5C00,0x5D00, - 0x5E00,0x5F00,0x6000,0x6100,0x6200,0x6300,0x6400,0x6500, - 0x6600,0x6700,0x6800,0x6900,0x6A00,0x6B00,0x6C00,0x6D00, - 0x6E00,0x6F00,0x7000,0x7100,0x7200,0x7300,0x7400,0x7500, - 0x7600,0x7700,0x7800,0x7900,0x7A00,0x7B00,0x7C00,0x7D00, - 0x7E00,0x7F00,0x8000,0x8100,0x8200,0x8300,0x8400,0x8500, - 0x8600,0x8700,0x8800,0x8900,0x8A00,0x8B00,0x8C00,0x8D00, - 0x8E00,0x8F00,0x9000,0x9100,0x9200,0x9300,0x9400,0x9500, - 0x9600,0x9700,0x9800,0x9900,0x9A00,0x9B00,0x9C00,0x9D00, - 0x9E00,0x9F00,0x0090,0x0110,0x0210,0x0310,0x0410,0x0510, - 0x0610,0x0710,0x0810,0x0910,0x0A10,0x0B10,0x0C10,0x0D10, - 0x0E10,0x0F10,0x1010,0x1110,0x1210,0x1310,0x1410,0x1510, - 0x1610,0x1710,0x1810,0x1910,0x1A10,0x1B10,0x1C10,0x1D10, - 0x1E10,0x1F10,0x2010,0x2110,0x2210,0x2310,0x2410,0x2510, - 0x2610,0x2710,0x2810,0x2910,0x2A10,0x2B10,0x2C10,0x2D10, - 0x2E10,0x2F10,0x3010,0x3110,0x3210,0x3310,0x3410,0x3510, - 0x3610,0x3710,0x3810,0x3910,0x3A10,0x3B10,0x3C10,0x3D10, - 0x3E10,0x3F10,0x4010,0x4110,0x4210,0x4310,0x4410,0x4510, - 0x4610,0x4710,0x4810,0x4910,0x4A10,0x4B10,0x4C10,0x4D10, - 0x4E10,0x4F10,0x5010,0x5110,0x5210,0x5310,0x5410,0x5510, - 0x5610,0x5710,0x5810,0x5910,0x5A10,0x5B10,0x5C10,0x5D10, - 0x5E10,0x5F10,0x6010,0x6110,0x6210,0x6310,0x6410,0x6510, - 0x6610,0x6710,0x6810,0x6910,0x6A10,0x6B10,0x6C10,0x6D10, - 0x6E10,0x6F10,0x7010,0x7110,0x7210,0x7310,0x7410,0x7510, - 0x7610,0x7710,0x7810,0x7910,0x7A10,0x7B10,0x7C10,0x7D10, - 0x7E10,0x7F10,0x8010,0x8110,0x8210,0x8310,0x8410,0x8510, - 0x8610,0x8710,0x8810,0x8910,0x8A10,0x8B10,0x8C10,0x8D10, - 0x8E10,0x8F10,0x9010,0x9110,0x9210,0x9310,0x9410,0x9510, - 0x9610,0x9710,0x9810,0x9910,0x9A10,0x9B10,0x9C10,0x9D10, - 0x9E10,0x9F10,0xA010,0xA110,0xA210,0xA310,0xA410,0xA510, - 0xA610,0xA710,0xA810,0xA910,0xAA10,0xAB10,0xAC10,0xAD10, - 0xAE10,0xAF10,0xB010,0xB110,0xB210,0xB310,0xB410,0xB510, - 0xB610,0xB710,0xB810,0xB910,0xBA10,0xBB10,0xBC10,0xBD10, - 0xBE10,0xBF10,0xC010,0xC110,0xC210,0xC310,0xC410,0xC510, - 0xC610,0xC710,0xC810,0xC910,0xCA10,0xCB10,0xCC10,0xCD10, - 0xCE10,0xCF10,0xD010,0xD110,0xD210,0xD310,0xD410,0xD510, - 0xD610,0xD710,0xD810,0xD910,0xDA10,0xDB10,0xDC10,0xDD10, - 0xDE10,0xDF10,0xE010,0xE110,0xE210,0xE310,0xE410,0xE510, - 0xE610,0xE710,0xE810,0xE910,0xEA10,0xEB10,0xEC10,0xED10, - 0xEE10,0xEF10,0xF010,0xF110,0xF210,0xF310,0xF410,0xF510, - 0xF610,0xF710,0xF810,0xF910,0xFA10,0xFB10,0xFC10,0xFD10, - 0xFE10,0xFF10,0x0090,0x0110,0x0210,0x0310,0x0410,0x0510, - 0x0610,0x0710,0x0810,0x0910,0x0A10,0x0B10,0x0C10,0x0D10, - 0x0E10,0x0F10,0x1010,0x1110,0x1210,0x1310,0x1410,0x1510, - 0x1610,0x1710,0x1810,0x1910,0x1A10,0x1B10,0x1C10,0x1D10, - 0x1E10,0x1F10,0x2010,0x2110,0x2210,0x2310,0x2410,0x2510, - 0x2610,0x2710,0x2810,0x2910,0x2A10,0x2B10,0x2C10,0x2D10, - 0x2E10,0x2F10,0x3010,0x3110,0x3210,0x3310,0x3410,0x3510, - 0x3610,0x3710,0x3810,0x3910,0x3A10,0x3B10,0x3C10,0x3D10, - 0x3E10,0x3F10,0x4010,0x4110,0x4210,0x4310,0x4410,0x4510, - 0x4610,0x4710,0x4810,0x4910,0x4A10,0x4B10,0x4C10,0x4D10, - 0x4E10,0x4F10,0x5010,0x5110,0x5210,0x5310,0x5410,0x5510, - 0x5610,0x5710,0x5810,0x5910,0x5A10,0x5B10,0x5C10,0x5D10, - 0x5E10,0x5F10,0x6010,0x6110,0x6210,0x6310,0x6410,0x6510, - 0x00C0,0x0140,0x0240,0x0340,0x0440,0x0540,0x0640,0x0740, - 0x0840,0x0940,0x0A40,0x0B40,0x0C40,0x0D40,0x0E40,0x0F40, - 0x1040,0x1140,0x1240,0x1340,0x1440,0x1540,0x1640,0x1740, - 0x1840,0x1940,0x1A40,0x1B40,0x1C40,0x1D40,0x1E40,0x1F40, - 0x2040,0x2140,0x2240,0x2340,0x2440,0x2540,0x2640,0x2740, - 0x2840,0x2940,0x2A40,0x2B40,0x2C40,0x2D40,0x2E40,0x2F40, - 0x3040,0x3140,0x3240,0x3340,0x3440,0x3540,0x3640,0x3740, - 0x3840,0x3940,0x3A40,0x3B40,0x3C40,0x3D40,0x3E40,0x3F40, - 0x4040,0x4140,0x4240,0x4340,0x4440,0x4540,0x4640,0x4740, - 0x4840,0x4940,0x4A40,0x4B40,0x4C40,0x4D40,0x4E40,0x4F40, - 0x5040,0x5140,0x5240,0x5340,0x5440,0x5540,0x5640,0x5740, - 0x5840,0x5940,0x5A40,0x5B40,0x5C40,0x5D40,0x5E40,0x5F40, - 0x6040,0x6140,0x6240,0x6340,0x6440,0x6540,0x6640,0x6740, - 0x6840,0x6940,0x6A40,0x6B40,0x6C40,0x6D40,0x6E40,0x6F40, - 0x7040,0x7140,0x7240,0x7340,0x7440,0x7540,0x7640,0x7740, - 0x7840,0x7940,0x7A40,0x7B40,0x7C40,0x7D40,0x7E40,0x7F40, - 0x8040,0x8140,0x8240,0x8340,0x8440,0x8540,0x8640,0x8740, - 0x8840,0x8940,0x8A40,0x8B40,0x8C40,0x8D40,0x8E40,0x8F40, - 0x9040,0x9140,0x9240,0x9340,0x9440,0x9540,0x9640,0x9740, - 0x9840,0x9940,0x9A40,0x9B40,0x9C40,0x9D40,0x9E40,0x9F40, - 0xA040,0xA140,0xA240,0xA340,0xA440,0xA540,0xA640,0xA740, - 0xA840,0xA940,0xAA40,0xAB40,0xAC40,0xAD40,0xAE40,0xAF40, - 0xB040,0xB140,0xB240,0xB340,0xB440,0xB540,0xB640,0xB740, - 0xB840,0xB940,0xBA40,0xBB40,0xBC40,0xBD40,0xBE40,0xBF40, - 0xC040,0xC140,0xC240,0xC340,0xC440,0xC540,0xC640,0xC740, - 0xC840,0xC940,0xCA40,0xCB40,0xCC40,0xCD40,0xCE40,0xCF40, - 0xD040,0xD140,0xD240,0xD340,0xD440,0xD540,0xD640,0xD740, - 0xD840,0xD940,0xDA40,0xDB40,0xDC40,0xDD40,0xDE40,0xDF40, - 0xE040,0xE140,0xE240,0xE340,0xE440,0xE540,0xE640,0xE740, - 0xE840,0xE940,0xEA40,0xEB40,0xEC40,0xED40,0xEE40,0xEF40, - 0xF040,0xF140,0xF240,0xF340,0xF440,0xF540,0xF640,0xF740, - 0xF840,0xF940,0xFA40,0xFB40,0xFC40,0xFD40,0xFE40,0xFF40, - 0xA050,0xA150,0xA250,0xA350,0xA450,0xA550,0xA650,0xA750, - 0xA850,0xA950,0xAA50,0xAB50,0xAC50,0xAD50,0xAE50,0xAF50, - 0xB050,0xB150,0xB250,0xB350,0xB450,0xB550,0xB650,0xB750, - 0xB850,0xB950,0xBA50,0xBB50,0xBC50,0xBD50,0xBE50,0xBF50, - 0xC050,0xC150,0xC250,0xC350,0xC450,0xC550,0xC650,0xC750, - 0xC850,0xC950,0xCA50,0xCB50,0xCC50,0xCD50,0xCE50,0xCF50, - 0xD050,0xD150,0xD250,0xD350,0xD450,0xD550,0xD650,0xD750, - 0xD850,0xD950,0xDA50,0xDB50,0xDC50,0xDD50,0xDE50,0xDF50, - 0xE050,0xE150,0xE250,0xE350,0xE450,0xE550,0xE650,0xE750, - 0xE850,0xE950,0xEA50,0xEB50,0xEC50,0xED50,0xEE50,0xEF50, - 0xF050,0xF150,0xF250,0xF350,0xF450,0xF550,0xF650,0xF750, - 0xF850,0xF950,0xFA50,0xFB50,0xFC50,0xFD50,0xFE50,0xFF50, - 0x00D0,0x0150,0x0250,0x0350,0x0450,0x0550,0x0650,0x0750, - 0x0850,0x0950,0x0A50,0x0B50,0x0C50,0x0D50,0x0E50,0x0F50, - 0x1050,0x1150,0x1250,0x1350,0x1450,0x1550,0x1650,0x1750, - 0x1850,0x1950,0x1A50,0x1B50,0x1C50,0x1D50,0x1E50,0x1F50, - 0x2050,0x2150,0x2250,0x2350,0x2450,0x2550,0x2650,0x2750, - 0x2850,0x2950,0x2A50,0x2B50,0x2C50,0x2D50,0x2E50,0x2F50, - 0x3050,0x3150,0x3250,0x3350,0x3450,0x3550,0x3650,0x3750, - 0x3850,0x3950,0x3A50,0x3B50,0x3C50,0x3D50,0x3E50,0x3F50, - 0x4050,0x4150,0x4250,0x4350,0x4450,0x4550,0x4650,0x4750, - 0x4850,0x4950,0x4A50,0x4B50,0x4C50,0x4D50,0x4E50,0x4F50, - 0x5050,0x5150,0x5250,0x5350,0x5450,0x5550,0x5650,0x5750, - 0x5850,0x5950,0x5A50,0x5B50,0x5C50,0x5D50,0x5E50,0x5F50, - 0x6050,0x6150,0x6250,0x6350,0x6450,0x6550,0x6650,0x6750, - 0x6850,0x6950,0x6A50,0x6B50,0x6C50,0x6D50,0x6E50,0x6F50, - 0x7050,0x7150,0x7250,0x7350,0x7450,0x7550,0x7650,0x7750, - 0x7850,0x7950,0x7A50,0x7B50,0x7C50,0x7D50,0x7E50,0x7F50, - 0x8050,0x8150,0x8250,0x8350,0x8450,0x8550,0x8650,0x8750, - 0x8850,0x8950,0x8A50,0x8B50,0x8C50,0x8D50,0x8E50,0x8F50, - 0x9050,0x9150,0x9250,0x9350,0x9450,0x9550,0x9650,0x9750, - 0x9850,0x9950,0x9A50,0x9B50,0x9C50,0x9D50,0x9E50,0x9F50, - 0xFA40,0xFB40,0xFC40,0xFD40,0xFE40,0xFF40,0x00C0,0x0140, - 0x0240,0x0340,0x0440,0x0540,0x0640,0x0740,0x0840,0x0940, - 0x0A40,0x0B40,0x0C40,0x0D40,0x0E40,0x0F40,0x1040,0x1140, - 0x1240,0x1340,0x1440,0x1540,0x1640,0x1740,0x1840,0x1940, - 0x1A40,0x1B40,0x1C40,0x1D40,0x1E40,0x1F40,0x2040,0x2140, - 0x2240,0x2340,0x2440,0x2540,0x2640,0x2740,0x2840,0x2940, - 0x2A40,0x2B40,0x2C40,0x2D40,0x2E40,0x2F40,0x3040,0x3140, - 0x3240,0x3340,0x3440,0x3540,0x3640,0x3740,0x3840,0x3940, - 0x3A40,0x3B40,0x3C40,0x3D40,0x3E40,0x3F40,0x4040,0x4140, - 0x4240,0x4340,0x4440,0x4540,0x4640,0x4740,0x4840,0x4940, - 0x4A40,0x4B40,0x4C40,0x4D40,0x4E40,0x4F40,0x5040,0x5140, - 0x5240,0x5340,0x5440,0x5540,0x5640,0x5740,0x5840,0x5940, - 0x5A40,0x5B40,0x5C40,0x5D40,0x5E40,0x5F40,0x6040,0x6140, - 0x6240,0x6340,0x6440,0x6540,0x6640,0x6740,0x6840,0x6940, - 0x6A40,0x6B40,0x6C40,0x6D40,0x6E40,0x6F40,0x7040,0x7140, - 0x7240,0x7340,0x7440,0x7540,0x7640,0x7740,0x7840,0x7940, - 0x7A40,0x7B40,0x7C40,0x7D40,0x7E40,0x7F40,0x8040,0x8140, - 0x8240,0x8340,0x8440,0x8540,0x8640,0x8740,0x8840,0x8940, - 0x8A40,0x8B40,0x8C40,0x8D40,0x8E40,0x8F40,0x9040,0x9140, - 0x9240,0x9340,0x9440,0x9540,0x9640,0x9740,0x9840,0x9940, - 0x9A40,0x9B40,0x9C40,0x9D40,0x9E40,0x9F40,0xA040,0xA140, - 0xA240,0xA340,0xA440,0xA540,0xA640,0xA740,0xA840,0xA940, - 0xAA40,0xAB40,0xAC40,0xAD40,0xAE40,0xAF40,0xB040,0xB140, - 0xB240,0xB340,0xB440,0xB540,0xB640,0xB740,0xB840,0xB940, - 0xBA40,0xBB40,0xBC40,0xBD40,0xBE40,0xBF40,0xC040,0xC140, - 0xC240,0xC340,0xC440,0xC540,0xC640,0xC740,0xC840,0xC940, - 0xCA40,0xCB40,0xCC40,0xCD40,0xCE40,0xCF40,0xD040,0xD140, - 0xD240,0xD340,0xD440,0xD540,0xD640,0xD740,0xD840,0xD940, - 0xDA40,0xDB40,0xDC40,0xDD40,0xDE40,0xDF40,0xE040,0xE140, - 0xE240,0xE340,0xE440,0xE540,0xE640,0xE740,0xE840,0xE940, - 0xEA40,0xEB40,0xEC40,0xED40,0xEE40,0xEF40,0xF040,0xF140, - 0xF240,0xF340,0xF440,0xF540,0xF640,0xF740,0xF840,0xF940, - 0x9A50,0x9B50,0x9C50,0x9D50,0x9E50,0x9F50,0xA050,0xA150, - 0xA250,0xA350,0xA450,0xA550,0xA650,0xA750,0xA850,0xA950, - 0xAA50,0xAB50,0xAC50,0xAD50,0xAE50,0xAF50,0xB050,0xB150, - 0xB250,0xB350,0xB450,0xB550,0xB650,0xB750,0xB850,0xB950, - 0xBA50,0xBB50,0xBC50,0xBD50,0xBE50,0xBF50,0xC050,0xC150, - 0xC250,0xC350,0xC450,0xC550,0xC650,0xC750,0xC850,0xC950, - 0xCA50,0xCB50,0xCC50,0xCD50,0xCE50,0xCF50,0xD050,0xD150, - 0xD250,0xD350,0xD450,0xD550,0xD650,0xD750,0xD850,0xD950, - 0xDA50,0xDB50,0xDC50,0xDD50,0xDE50,0xDF50,0xE050,0xE150, - 0xE250,0xE350,0xE450,0xE550,0xE650,0xE750,0xE850,0xE950, - 0xEA50,0xEB50,0xEC50,0xED50,0xEE50,0xEF50,0xF050,0xF150, - 0xF250,0xF350,0xF450,0xF550,0xF650,0xF750,0xF850,0xF950, - 0xFA50,0xFB50,0xFC50,0xFD50,0xFE50,0xFF50,0x00D0,0x0150, - 0x0250,0x0350,0x0450,0x0550,0x0650,0x0750,0x0850,0x0950, - 0x0A50,0x0B50,0x0C50,0x0D50,0x0E50,0x0F50,0x1050,0x1150, - 0x1250,0x1350,0x1450,0x1550,0x1650,0x1750,0x1850,0x1950, - 0x1A50,0x1B50,0x1C50,0x1D50,0x1E50,0x1F50,0x2050,0x2150, - 0x2250,0x2350,0x2450,0x2550,0x2650,0x2750,0x2850,0x2950, - 0x2A50,0x2B50,0x2C50,0x2D50,0x2E50,0x2F50,0x3050,0x3150, - 0x3250,0x3350,0x3450,0x3550,0x3650,0x3750,0x3850,0x3950, - 0x3A50,0x3B50,0x3C50,0x3D50,0x3E50,0x3F50,0x4050,0x4150, - 0x4250,0x4350,0x4450,0x4550,0x4650,0x4750,0x4850,0x4950, - 0x4A50,0x4B50,0x4C50,0x4D50,0x4E50,0x4F50,0x5050,0x5150, - 0x5250,0x5350,0x5450,0x5550,0x5650,0x5750,0x5850,0x5950, - 0x5A50,0x5B50,0x5C50,0x5D50,0x5E50,0x5F50,0x6050,0x6150, - 0x6250,0x6350,0x6450,0x6550,0x6650,0x6750,0x6850,0x6950, - 0x6A50,0x6B50,0x6C50,0x6D50,0x6E50,0x6F50,0x7050,0x7150, - 0x7250,0x7350,0x7450,0x7550,0x7650,0x7750,0x7850,0x7950, - 0x7A50,0x7B50,0x7C50,0x7D50,0x7E50,0x7F50,0x8050,0x8150, - 0x8250,0x8350,0x8450,0x8550,0x8650,0x8750,0x8850,0x8950, - 0x8A50,0x8B50,0x8C50,0x8D50,0x8E50,0x8F50,0x9050,0x9150, - 0x9250,0x9350,0x9450,0x9550,0x9650,0x9750,0x9850,0x9950, + 0x0080, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, + 0x0800, 0x0900, 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, + 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, + 0x1800, 0x1900, 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, + 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700, + 0x2800, 0x2900, 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, + 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, + 0x3800, 0x3900, 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, + 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, + 0x4800, 0x4900, 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, + 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, + 0x5800, 0x5900, 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, + 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, 0x6700, + 0x6800, 0x6900, 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, + 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, + 0x7800, 0x7900, 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, + 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, + 0x8800, 0x8900, 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, + 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700, + 0x9800, 0x9900, 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, + 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, + 0x0810, 0x0910, 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, + 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, + 0x1810, 0x1910, 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, + 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, + 0x2810, 0x2910, 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, + 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, + 0x3810, 0x3910, 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, + 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, + 0x4810, 0x4910, 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, + 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, + 0x5810, 0x5910, 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, + 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, 0x6610, 0x6710, + 0x6810, 0x6910, 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, + 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, 0x7610, 0x7710, + 0x7810, 0x7910, 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, + 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, 0x8610, 0x8710, + 0x8810, 0x8910, 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, + 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, 0x9610, 0x9710, + 0x9810, 0x9910, 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, + 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, 0xA610, 0xA710, + 0xA810, 0xA910, 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, + 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, 0xB610, 0xB710, + 0xB810, 0xB910, 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, + 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, 0xC610, 0xC710, + 0xC810, 0xC910, 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, + 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, 0xD610, 0xD710, + 0xD810, 0xD910, 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, + 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, 0xE610, 0xE710, + 0xE810, 0xE910, 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, + 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, 0xF610, 0xF710, + 0xF810, 0xF910, 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, + 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, + 0x0810, 0x0910, 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, + 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, + 0x1810, 0x1910, 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, + 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, + 0x2810, 0x2910, 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, + 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, + 0x3810, 0x3910, 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, + 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, + 0x4810, 0x4910, 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, + 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, + 0x5810, 0x5910, 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, + 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, + 0x0E00, 0x0F00, 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, + 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, + 0x1E00, 0x1F00, 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, + 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00, + 0x2E00, 0x2F00, 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, + 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00, + 0x3E00, 0x3F00, 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, + 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, + 0x4E00, 0x4F00, 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, + 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00, + 0x5E00, 0x5F00, 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, + 0x6600, 0x6700, 0x6800, 0x6900, 0x6A00, 0x6B00, 0x6C00, 0x6D00, + 0x6E00, 0x6F00, 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, + 0x7600, 0x7700, 0x7800, 0x7900, 0x7A00, 0x7B00, 0x7C00, 0x7D00, + 0x7E00, 0x7F00, 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, + 0x8600, 0x8700, 0x8800, 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x8D00, + 0x8E00, 0x8F00, 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, + 0x9600, 0x9700, 0x9800, 0x9900, 0x9A00, 0x9B00, 0x9C00, 0x9D00, + 0x9E00, 0x9F00, 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, + 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, + 0x0E10, 0x0F10, 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, + 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, + 0x1E10, 0x1F10, 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, + 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, + 0x2E10, 0x2F10, 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, + 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, + 0x3E10, 0x3F10, 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, + 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, + 0x4E10, 0x4F10, 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, + 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, + 0x5E10, 0x5F10, 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, + 0x6610, 0x6710, 0x6810, 0x6910, 0x6A10, 0x6B10, 0x6C10, 0x6D10, + 0x6E10, 0x6F10, 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, + 0x7610, 0x7710, 0x7810, 0x7910, 0x7A10, 0x7B10, 0x7C10, 0x7D10, + 0x7E10, 0x7F10, 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, + 0x8610, 0x8710, 0x8810, 0x8910, 0x8A10, 0x8B10, 0x8C10, 0x8D10, + 0x8E10, 0x8F10, 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, + 0x9610, 0x9710, 0x9810, 0x9910, 0x9A10, 0x9B10, 0x9C10, 0x9D10, + 0x9E10, 0x9F10, 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, + 0xA610, 0xA710, 0xA810, 0xA910, 0xAA10, 0xAB10, 0xAC10, 0xAD10, + 0xAE10, 0xAF10, 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, + 0xB610, 0xB710, 0xB810, 0xB910, 0xBA10, 0xBB10, 0xBC10, 0xBD10, + 0xBE10, 0xBF10, 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, + 0xC610, 0xC710, 0xC810, 0xC910, 0xCA10, 0xCB10, 0xCC10, 0xCD10, + 0xCE10, 0xCF10, 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, + 0xD610, 0xD710, 0xD810, 0xD910, 0xDA10, 0xDB10, 0xDC10, 0xDD10, + 0xDE10, 0xDF10, 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, + 0xE610, 0xE710, 0xE810, 0xE910, 0xEA10, 0xEB10, 0xEC10, 0xED10, + 0xEE10, 0xEF10, 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, + 0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, 0xFC10, 0xFD10, + 0xFE10, 0xFF10, 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, + 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, + 0x0E10, 0x0F10, 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, + 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, + 0x1E10, 0x1F10, 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, + 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, + 0x2E10, 0x2F10, 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, + 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, + 0x3E10, 0x3F10, 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, + 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, + 0x4E10, 0x4F10, 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, + 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, + 0x5E10, 0x5F10, 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, + 0x00C0, 0x0140, 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, + 0x0840, 0x0940, 0x0A40, 0x0B40, 0x0C40, 0x0D40, 0x0E40, 0x0F40, + 0x1040, 0x1140, 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, + 0x1840, 0x1940, 0x1A40, 0x1B40, 0x1C40, 0x1D40, 0x1E40, 0x1F40, + 0x2040, 0x2140, 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, + 0x2840, 0x2940, 0x2A40, 0x2B40, 0x2C40, 0x2D40, 0x2E40, 0x2F40, + 0x3040, 0x3140, 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, + 0x3840, 0x3940, 0x3A40, 0x3B40, 0x3C40, 0x3D40, 0x3E40, 0x3F40, + 0x4040, 0x4140, 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, + 0x4840, 0x4940, 0x4A40, 0x4B40, 0x4C40, 0x4D40, 0x4E40, 0x4F40, + 0x5040, 0x5140, 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, + 0x5840, 0x5940, 0x5A40, 0x5B40, 0x5C40, 0x5D40, 0x5E40, 0x5F40, + 0x6040, 0x6140, 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, + 0x6840, 0x6940, 0x6A40, 0x6B40, 0x6C40, 0x6D40, 0x6E40, 0x6F40, + 0x7040, 0x7140, 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, + 0x7840, 0x7940, 0x7A40, 0x7B40, 0x7C40, 0x7D40, 0x7E40, 0x7F40, + 0x8040, 0x8140, 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, + 0x8840, 0x8940, 0x8A40, 0x8B40, 0x8C40, 0x8D40, 0x8E40, 0x8F40, + 0x9040, 0x9140, 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740, + 0x9840, 0x9940, 0x9A40, 0x9B40, 0x9C40, 0x9D40, 0x9E40, 0x9F40, + 0xA040, 0xA140, 0xA240, 0xA340, 0xA440, 0xA540, 0xA640, 0xA740, + 0xA840, 0xA940, 0xAA40, 0xAB40, 0xAC40, 0xAD40, 0xAE40, 0xAF40, + 0xB040, 0xB140, 0xB240, 0xB340, 0xB440, 0xB540, 0xB640, 0xB740, + 0xB840, 0xB940, 0xBA40, 0xBB40, 0xBC40, 0xBD40, 0xBE40, 0xBF40, + 0xC040, 0xC140, 0xC240, 0xC340, 0xC440, 0xC540, 0xC640, 0xC740, + 0xC840, 0xC940, 0xCA40, 0xCB40, 0xCC40, 0xCD40, 0xCE40, 0xCF40, + 0xD040, 0xD140, 0xD240, 0xD340, 0xD440, 0xD540, 0xD640, 0xD740, + 0xD840, 0xD940, 0xDA40, 0xDB40, 0xDC40, 0xDD40, 0xDE40, 0xDF40, + 0xE040, 0xE140, 0xE240, 0xE340, 0xE440, 0xE540, 0xE640, 0xE740, + 0xE840, 0xE940, 0xEA40, 0xEB40, 0xEC40, 0xED40, 0xEE40, 0xEF40, + 0xF040, 0xF140, 0xF240, 0xF340, 0xF440, 0xF540, 0xF640, 0xF740, + 0xF840, 0xF940, 0xFA40, 0xFB40, 0xFC40, 0xFD40, 0xFE40, 0xFF40, + 0xA050, 0xA150, 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, + 0xA850, 0xA950, 0xAA50, 0xAB50, 0xAC50, 0xAD50, 0xAE50, 0xAF50, + 0xB050, 0xB150, 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, + 0xB850, 0xB950, 0xBA50, 0xBB50, 0xBC50, 0xBD50, 0xBE50, 0xBF50, + 0xC050, 0xC150, 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, + 0xC850, 0xC950, 0xCA50, 0xCB50, 0xCC50, 0xCD50, 0xCE50, 0xCF50, + 0xD050, 0xD150, 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, + 0xD850, 0xD950, 0xDA50, 0xDB50, 0xDC50, 0xDD50, 0xDE50, 0xDF50, + 0xE050, 0xE150, 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, + 0xE850, 0xE950, 0xEA50, 0xEB50, 0xEC50, 0xED50, 0xEE50, 0xEF50, + 0xF050, 0xF150, 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, + 0xF850, 0xF950, 0xFA50, 0xFB50, 0xFC50, 0xFD50, 0xFE50, 0xFF50, + 0x00D0, 0x0150, 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, + 0x0850, 0x0950, 0x0A50, 0x0B50, 0x0C50, 0x0D50, 0x0E50, 0x0F50, + 0x1050, 0x1150, 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, + 0x1850, 0x1950, 0x1A50, 0x1B50, 0x1C50, 0x1D50, 0x1E50, 0x1F50, + 0x2050, 0x2150, 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, + 0x2850, 0x2950, 0x2A50, 0x2B50, 0x2C50, 0x2D50, 0x2E50, 0x2F50, + 0x3050, 0x3150, 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, + 0x3850, 0x3950, 0x3A50, 0x3B50, 0x3C50, 0x3D50, 0x3E50, 0x3F50, + 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, + 0x4850, 0x4950, 0x4A50, 0x4B50, 0x4C50, 0x4D50, 0x4E50, 0x4F50, + 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, + 0x5850, 0x5950, 0x5A50, 0x5B50, 0x5C50, 0x5D50, 0x5E50, 0x5F50, + 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, + 0x6850, 0x6950, 0x6A50, 0x6B50, 0x6C50, 0x6D50, 0x6E50, 0x6F50, + 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, + 0x7850, 0x7950, 0x7A50, 0x7B50, 0x7C50, 0x7D50, 0x7E50, 0x7F50, + 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, + 0x8850, 0x8950, 0x8A50, 0x8B50, 0x8C50, 0x8D50, 0x8E50, 0x8F50, + 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, + 0x9850, 0x9950, 0x9A50, 0x9B50, 0x9C50, 0x9D50, 0x9E50, 0x9F50, + 0xFA40, 0xFB40, 0xFC40, 0xFD40, 0xFE40, 0xFF40, 0x00C0, 0x0140, + 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, + 0x0A40, 0x0B40, 0x0C40, 0x0D40, 0x0E40, 0x0F40, 0x1040, 0x1140, + 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, + 0x1A40, 0x1B40, 0x1C40, 0x1D40, 0x1E40, 0x1F40, 0x2040, 0x2140, + 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, + 0x2A40, 0x2B40, 0x2C40, 0x2D40, 0x2E40, 0x2F40, 0x3040, 0x3140, + 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, + 0x3A40, 0x3B40, 0x3C40, 0x3D40, 0x3E40, 0x3F40, 0x4040, 0x4140, + 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, + 0x4A40, 0x4B40, 0x4C40, 0x4D40, 0x4E40, 0x4F40, 0x5040, 0x5140, + 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, + 0x5A40, 0x5B40, 0x5C40, 0x5D40, 0x5E40, 0x5F40, 0x6040, 0x6140, + 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, + 0x6A40, 0x6B40, 0x6C40, 0x6D40, 0x6E40, 0x6F40, 0x7040, 0x7140, + 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, + 0x7A40, 0x7B40, 0x7C40, 0x7D40, 0x7E40, 0x7F40, 0x8040, 0x8140, + 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, + 0x8A40, 0x8B40, 0x8C40, 0x8D40, 0x8E40, 0x8F40, 0x9040, 0x9140, + 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740, 0x9840, 0x9940, + 0x9A40, 0x9B40, 0x9C40, 0x9D40, 0x9E40, 0x9F40, 0xA040, 0xA140, + 0xA240, 0xA340, 0xA440, 0xA540, 0xA640, 0xA740, 0xA840, 0xA940, + 0xAA40, 0xAB40, 0xAC40, 0xAD40, 0xAE40, 0xAF40, 0xB040, 0xB140, + 0xB240, 0xB340, 0xB440, 0xB540, 0xB640, 0xB740, 0xB840, 0xB940, + 0xBA40, 0xBB40, 0xBC40, 0xBD40, 0xBE40, 0xBF40, 0xC040, 0xC140, + 0xC240, 0xC340, 0xC440, 0xC540, 0xC640, 0xC740, 0xC840, 0xC940, + 0xCA40, 0xCB40, 0xCC40, 0xCD40, 0xCE40, 0xCF40, 0xD040, 0xD140, + 0xD240, 0xD340, 0xD440, 0xD540, 0xD640, 0xD740, 0xD840, 0xD940, + 0xDA40, 0xDB40, 0xDC40, 0xDD40, 0xDE40, 0xDF40, 0xE040, 0xE140, + 0xE240, 0xE340, 0xE440, 0xE540, 0xE640, 0xE740, 0xE840, 0xE940, + 0xEA40, 0xEB40, 0xEC40, 0xED40, 0xEE40, 0xEF40, 0xF040, 0xF140, + 0xF240, 0xF340, 0xF440, 0xF540, 0xF640, 0xF740, 0xF840, 0xF940, + 0x9A50, 0x9B50, 0x9C50, 0x9D50, 0x9E50, 0x9F50, 0xA050, 0xA150, + 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, + 0xAA50, 0xAB50, 0xAC50, 0xAD50, 0xAE50, 0xAF50, 0xB050, 0xB150, + 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, + 0xBA50, 0xBB50, 0xBC50, 0xBD50, 0xBE50, 0xBF50, 0xC050, 0xC150, + 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, + 0xCA50, 0xCB50, 0xCC50, 0xCD50, 0xCE50, 0xCF50, 0xD050, 0xD150, + 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, + 0xDA50, 0xDB50, 0xDC50, 0xDD50, 0xDE50, 0xDF50, 0xE050, 0xE150, + 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, + 0xEA50, 0xEB50, 0xEC50, 0xED50, 0xEE50, 0xEF50, 0xF050, 0xF150, + 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, + 0xFA50, 0xFB50, 0xFC50, 0xFD50, 0xFE50, 0xFF50, 0x00D0, 0x0150, + 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, + 0x0A50, 0x0B50, 0x0C50, 0x0D50, 0x0E50, 0x0F50, 0x1050, 0x1150, + 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, + 0x1A50, 0x1B50, 0x1C50, 0x1D50, 0x1E50, 0x1F50, 0x2050, 0x2150, + 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, + 0x2A50, 0x2B50, 0x2C50, 0x2D50, 0x2E50, 0x2F50, 0x3050, 0x3150, + 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x3A50, 0x3B50, 0x3C50, 0x3D50, 0x3E50, 0x3F50, 0x4050, 0x4150, + 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x4A50, 0x4B50, 0x4C50, 0x4D50, 0x4E50, 0x4F50, 0x5050, 0x5150, + 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x5A50, 0x5B50, 0x5C50, 0x5D50, 0x5E50, 0x5F50, 0x6050, 0x6150, + 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x6A50, 0x6B50, 0x6C50, 0x6D50, 0x6E50, 0x6F50, 0x7050, 0x7150, + 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x7A50, 0x7B50, 0x7C50, 0x7D50, 0x7E50, 0x7F50, 0x8050, 0x8150, + 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x8A50, 0x8B50, 0x8C50, 0x8D50, 0x8E50, 0x8F50, 0x9050, 0x9150, + 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, }; uint8_t ZeroTable[256] = { - 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0 + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; // Title checksums that are treated specially by the CGB boot ROM static const uint8_t gbColorizationChecksums[79] = { - 0x00, 0x88, 0x16, 0x36, 0xD1, 0xDB, 0xF2, 0x3C, 0x8C, 0x92, 0x3D, 0x5C, - 0x58, 0xC9, 0x3E, 0x70, 0x1D, 0x59, 0x69, 0x19, 0x35, 0xA8, 0x14, 0xAA, - 0x75, 0x95, 0x99, 0x34, 0x6F, 0x15, 0xFF, 0x97, 0x4B, 0x90, 0x17, 0x10, - 0x39, 0xF7, 0xF6, 0xA2, 0x49, 0x4E, 0x43, 0x68, 0xE0, 0x8B, 0xF0, 0xCE, - 0x0C, 0x29, 0xE8, 0xB7, 0x86, 0x9A, 0x52, 0x01, 0x9D, 0x71, 0x9C, 0xBD, - 0x5D, 0x6D, 0x67, 0x3F, 0x6B, 0xB3, 0x46, 0x28, 0xA5, 0xC6, 0xD3, 0x27, - 0x61, 0x18, 0x66, 0x6A, 0xBF, 0x0D, 0xF4 + 0x00, 0x88, 0x16, 0x36, 0xD1, 0xDB, 0xF2, 0x3C, 0x8C, 0x92, 0x3D, 0x5C, + 0x58, 0xC9, 0x3E, 0x70, 0x1D, 0x59, 0x69, 0x19, 0x35, 0xA8, 0x14, 0xAA, + 0x75, 0x95, 0x99, 0x34, 0x6F, 0x15, 0xFF, 0x97, 0x4B, 0x90, 0x17, 0x10, + 0x39, 0xF7, 0xF6, 0xA2, 0x49, 0x4E, 0x43, 0x68, 0xE0, 0x8B, 0xF0, 0xCE, + 0x0C, 0x29, 0xE8, 0xB7, 0x86, 0x9A, 0x52, 0x01, 0x9D, 0x71, 0x9C, 0xBD, + 0x5D, 0x6D, 0x67, 0x3F, 0x6B, 0xB3, 0x46, 0x28, 0xA5, 0xC6, 0xD3, 0x27, + 0x61, 0x18, 0x66, 0x6A, 0xBF, 0x0D, 0xF4 }; // For titles with colliding checksums, the fourth character of the game title // for disambiguation. static const uint8_t gbColorizationDisambigChars[29] = { - 'B', 'E', 'F', 'A', 'A', 'R', 'B', 'E', - 'K', 'E', 'K', ' ', 'R', '-', 'U', 'R', - 'A', 'R', ' ', 'I', 'N', 'A', 'I', 'L', - 'I', 'C', 'E', ' ', 'R' + 'B', 'E', 'F', 'A', 'A', 'R', 'B', 'E', + 'K', 'E', 'K', ' ', 'R', '-', 'U', 'R', + 'A', 'R', ' ', 'I', 'N', 'A', 'I', 'L', + 'I', 'C', 'E', ' ', 'R' }; // Palette ID | (Flags << 5) static const uint8_t gbColorizationPaletteInfo[94] = { - 0x7C, 0x08, 0x12, 0xA3, 0xA2, 0x07, 0x87, 0x4B, 0x20, 0x12, 0x65, 0xA8, - 0x16, 0xA9, 0x86, 0xB1, 0x68, 0xA0, 0x87, 0x66, 0x12, 0xA1, 0x30, 0x3C, - 0x12, 0x85, 0x12, 0x64, 0x1B, 0x07, 0x06, 0x6F, 0x6E, 0x6E, 0xAE, 0xAF, - 0x6F, 0xB2, 0xAF, 0xB2, 0xA8, 0xAB, 0x6F, 0xAF, 0x86, 0xAE, 0xA2, 0xA2, - 0x12, 0xAF, 0x13, 0x12, 0xA1, 0x6E, 0xAF, 0xAF, 0xAD, 0x06, 0x4C, 0x6E, - 0xAF, 0xAF, 0x12, 0x7C, 0xAC, 0xA8, 0x6A, 0x6E, 0x13, 0xA0, 0x2D, 0xA8, - 0x2B, 0xAC, 0x64, 0xAC, 0x6D, 0x87, 0xBC, 0x60, 0xB4, 0x13, 0x72, 0x7C, - 0xB5, 0xAE, 0xAE, 0x7C, 0x7C, 0x65, 0xA2, 0x6C, 0x64, 0x85 + 0x7C, 0x08, 0x12, 0xA3, 0xA2, 0x07, 0x87, 0x4B, 0x20, 0x12, 0x65, 0xA8, + 0x16, 0xA9, 0x86, 0xB1, 0x68, 0xA0, 0x87, 0x66, 0x12, 0xA1, 0x30, 0x3C, + 0x12, 0x85, 0x12, 0x64, 0x1B, 0x07, 0x06, 0x6F, 0x6E, 0x6E, 0xAE, 0xAF, + 0x6F, 0xB2, 0xAF, 0xB2, 0xA8, 0xAB, 0x6F, 0xAF, 0x86, 0xAE, 0xA2, 0xA2, + 0x12, 0xAF, 0x13, 0x12, 0xA1, 0x6E, 0xAF, 0xAF, 0xAD, 0x06, 0x4C, 0x6E, + 0xAF, 0xAF, 0x12, 0x7C, 0xAC, 0xA8, 0x6A, 0x6E, 0x13, 0xA0, 0x2D, 0xA8, + 0x2B, 0xAC, 0x64, 0xAC, 0x6D, 0x87, 0xBC, 0x60, 0xB4, 0x13, 0x72, 0x7C, + 0xB5, 0xAE, 0xAE, 0x7C, 0x7C, 0x65, 0xA2, 0x6C, 0x64, 0x85 }; - // Uncompressed palette data from the CGB boot ROM static const uint16_t gbColorizationPaletteData[32][3][4] = { - { - { 0x7FFF, 0x01DF, 0x0112, 0x0000 }, - { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, - { 0x7FFF, 0x42B5, 0x3DC8, 0x0000 }, - }, - { - { 0x231F, 0x035F, 0x00F2, 0x0009 }, - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x4FFF, 0x7ED2, 0x3A4C, 0x1CE0 }, - }, - { - { 0x7FFF, 0x7FFF, 0x7E8C, 0x7C00 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x03ED, 0x7FFF, 0x255F, 0x0000 }, - }, - { - { 0x7FFF, 0x7FFF, 0x7E8C, 0x7C00 }, - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x036A, 0x021F, 0x03FF, 0x7FFF }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x03EF, 0x01D6, 0x0000 }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, - { 0x7FFF, 0x03EA, 0x011F, 0x0000 }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, - { 0x7FFF, 0x027F, 0x001F, 0x0000 }, - }, - { - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, - { 0x7FFF, 0x03FF, 0x001F, 0x0000 }, - }, - { - { 0x299F, 0x001A, 0x000C, 0x0000 }, - { 0x7C00, 0x7FFF, 0x3FFF, 0x7E00 }, - { 0x7E74, 0x03FF, 0x0180, 0x0000 }, - }, - { - { 0x7FFF, 0x01DF, 0x0112, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x67FF, 0x77AC, 0x1A13, 0x2D6B }, - }, - { - { 0x0000, 0x7FFF, 0x421F, 0x1CF2 }, - { 0x0000, 0x7FFF, 0x421F, 0x1CF2 }, - { 0x7ED6, 0x4BFF, 0x2175, 0x0000 }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x3FFF, 0x7E00, 0x001F }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - }, - { - { 0x231F, 0x035F, 0x00F2, 0x0009 }, - { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, - { 0x7FFF, 0x6E31, 0x454A, 0x0000 }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x7FFF, 0x6E31, 0x454A, 0x0000 }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - }, - { - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - }, - { - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - }, - { - { 0x7FFF, 0x03E0, 0x0206, 0x0120 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - }, - { - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - { 0x0000, 0x4200, 0x037F, 0x7FFF }, - }, - { - { 0x03FF, 0x001F, 0x000C, 0x0000 }, - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - }, - { - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x42B5, 0x3DC8, 0x0000 }, - }, - { - { 0x7FFF, 0x5294, 0x294A, 0x0000 }, - { 0x7FFF, 0x5294, 0x294A, 0x0000 }, - { 0x7FFF, 0x5294, 0x294A, 0x0000 }, - }, - { - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x53FF, 0x4A5F, 0x7E52, 0x0000 }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - }, - { - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x639F, 0x4279, 0x15B0, 0x04CB }, - }, - { - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, - { 0x7FFF, 0x03FF, 0x012F, 0x0000 }, - }, - { - { 0x7FFF, 0x033F, 0x0193, 0x0000 }, - { 0x7FFF, 0x033F, 0x0193, 0x0000 }, - { 0x7FFF, 0x033F, 0x0193, 0x0000 }, - }, - { - { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, - { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, - { 0x7FFF, 0x1BEF, 0x6180, 0x0000 }, - }, - { - { 0x2120, 0x8022, 0x8281, 0x1110 }, - { 0xFF7F, 0xDF7F, 0x1201, 0x0001 }, - { 0xFF00, 0xFF7F, 0x1F03, 0x0000 }, - }, - { - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - }, - { - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, - } + { + { 0x7FFF, 0x01DF, 0x0112, 0x0000 }, + { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, + { 0x7FFF, 0x42B5, 0x3DC8, 0x0000 }, + }, + { + { 0x231F, 0x035F, 0x00F2, 0x0009 }, + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x4FFF, 0x7ED2, 0x3A4C, 0x1CE0 }, + }, + { + { 0x7FFF, 0x7FFF, 0x7E8C, 0x7C00 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x03ED, 0x7FFF, 0x255F, 0x0000 }, + }, + { + { 0x7FFF, 0x7FFF, 0x7E8C, 0x7C00 }, + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x036A, 0x021F, 0x03FF, 0x7FFF }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x03EF, 0x01D6, 0x0000 }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, + { 0x7FFF, 0x03EA, 0x011F, 0x0000 }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, + { 0x7FFF, 0x027F, 0x001F, 0x0000 }, + }, + { + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, + { 0x7FFF, 0x03FF, 0x001F, 0x0000 }, + }, + { + { 0x299F, 0x001A, 0x000C, 0x0000 }, + { 0x7C00, 0x7FFF, 0x3FFF, 0x7E00 }, + { 0x7E74, 0x03FF, 0x0180, 0x0000 }, + }, + { + { 0x7FFF, 0x01DF, 0x0112, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x67FF, 0x77AC, 0x1A13, 0x2D6B }, + }, + { + { 0x0000, 0x7FFF, 0x421F, 0x1CF2 }, + { 0x0000, 0x7FFF, 0x421F, 0x1CF2 }, + { 0x7ED6, 0x4BFF, 0x2175, 0x0000 }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x3FFF, 0x7E00, 0x001F }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + }, + { + { 0x231F, 0x035F, 0x00F2, 0x0009 }, + { 0x7FFF, 0x7EEB, 0x001F, 0x7C00 }, + { 0x7FFF, 0x6E31, 0x454A, 0x0000 }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x7FFF, 0x6E31, 0x454A, 0x0000 }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + }, + { + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + }, + { + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + }, + { + { 0x7FFF, 0x03E0, 0x0206, 0x0120 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + }, + { + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + { 0x0000, 0x4200, 0x037F, 0x7FFF }, + }, + { + { 0x03FF, 0x001F, 0x000C, 0x0000 }, + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + }, + { + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x42B5, 0x3DC8, 0x0000 }, + }, + { + { 0x7FFF, 0x5294, 0x294A, 0x0000 }, + { 0x7FFF, 0x5294, 0x294A, 0x0000 }, + { 0x7FFF, 0x5294, 0x294A, 0x0000 }, + }, + { + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x53FF, 0x4A5F, 0x7E52, 0x0000 }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + }, + { + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x639F, 0x4279, 0x15B0, 0x04CB }, + }, + { + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x1BEF, 0x0200, 0x0000 }, + { 0x7FFF, 0x03FF, 0x012F, 0x0000 }, + }, + { + { 0x7FFF, 0x033F, 0x0193, 0x0000 }, + { 0x7FFF, 0x033F, 0x0193, 0x0000 }, + { 0x7FFF, 0x033F, 0x0193, 0x0000 }, + }, + { + { 0x7FFF, 0x421F, 0x1CF2, 0x0000 }, + { 0x7FFF, 0x7E8C, 0x7C00, 0x0000 }, + { 0x7FFF, 0x1BEF, 0x6180, 0x0000 }, + }, + { + { 0x2120, 0x8022, 0x8281, 0x1110 }, + { 0xFF7F, 0xDF7F, 0x1201, 0x0001 }, + { 0xFF00, 0xFF7F, 0x1F03, 0x0000 }, + }, + { + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + }, + { + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + { 0x7FFF, 0x32BF, 0x00D0, 0x0000 }, + } }; - - #define GBSAVE_GAME_VERSION_1 1 #define GBSAVE_GAME_VERSION_2 2 #define GBSAVE_GAME_VERSION_3 3 @@ -777,387 +774,367 @@ static const uint16_t gbColorizationPaletteData[32][3][4] = { #define GBSAVE_GAME_VERSION_12 12 #define GBSAVE_GAME_VERSION GBSAVE_GAME_VERSION_12 -int inline gbGetValue(int min,int max,int v) +int inline gbGetValue(int min, int max, int v) { - return (int)(min+(float)(max-min)*(2.0*(v/31.0)-(v/31.0)*(v/31.0))); + return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0))); } void gbGenFilter() { - for (int r=0;r<32;r++) { - for (int g=0;g<32;g++) { - for (int b=0;b<32;b++) { - int nr=gbGetValue(gbGetValue(4,14,g), - gbGetValue(24,29,g),r)-4; - int ng=gbGetValue(gbGetValue(4+gbGetValue(0,5,r), - 14+gbGetValue(0,3,r),b), - gbGetValue(24+gbGetValue(0,3,r), - 29+gbGetValue(0,1,r),b),g)-4; - int nb=gbGetValue(gbGetValue(4+gbGetValue(0,5,r), - 14+gbGetValue(0,3,r),g), - gbGetValue(24+gbGetValue(0,3,r), - 29+gbGetValue(0,1,r),g),b)-4; - gbColorFilter[(b<<10)|(g<<5)|r]=(nb<<10)|(ng<<5)|nr; - } + for (int 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; + } + } } - } } -bool gbIsGameboyRom(char * file) +bool gbIsGameboyRom(char* file) { - if(strlen(file) > 4) { - char * p = strrchr(file,'.'); + if (strlen(file) > 4) { + char* p = strrchr(file, '.'); - if(p != NULL) { - if(_stricmp(p, ".gb") == 0) - return true; - if(_stricmp(p, ".dmg") == 0) - return true; - if(_stricmp(p, ".gbc") == 0) - return true; - if(_stricmp(p, ".cgb") == 0) - return true; - if(_stricmp(p, ".sgb") == 0) - return true; + if (p != NULL) { + if (_stricmp(p, ".gb") == 0) + return true; + if (_stricmp(p, ".dmg") == 0) + return true; + if (_stricmp(p, ".gbc") == 0) + return true; + if (_stricmp(p, ".cgb") == 0) + return true; + if (_stricmp(p, ".sgb") == 0) + return true; + } } - } - return false; + return false; } void gbCopyMemory(uint16_t d, uint16_t s, int count) { - while(count) { - gbMemoryMap[d>>12][d & 0x0fff] = gbMemoryMap[s>>12][s & 0x0fff]; - s++; - d++; - count--; - } + while (count) { + gbMemoryMap[d >> 12][d & 0x0fff] = gbMemoryMap[s >> 12][s & 0x0fff]; + s++; + d++; + count--; + } } void gbDoHdma() { - gbCopyMemory((gbHdmaDestination & 0x1ff0) | 0x8000, - gbHdmaSource & 0xfff0, - 0x10); + gbCopyMemory((gbHdmaDestination & 0x1ff0) | 0x8000, + gbHdmaSource & 0xfff0, + 0x10); - gbHdmaDestination += 0x10; - if (gbHdmaDestination == 0xa000) - gbHdmaDestination = 0x8000; + gbHdmaDestination += 0x10; + if (gbHdmaDestination == 0xa000) + gbHdmaDestination = 0x8000; - gbHdmaSource += 0x10; - if (gbHdmaSource == 0x8000) - gbHdmaSource = 0xa000; + gbHdmaSource += 0x10; + if (gbHdmaSource == 0x8000) + gbHdmaSource = 0xa000; - register_HDMA2 = gbHdmaSource & 0xff; - register_HDMA1 = gbHdmaSource>>8; + register_HDMA2 = gbHdmaSource & 0xff; + register_HDMA1 = gbHdmaSource >> 8; - register_HDMA4 = gbHdmaDestination & 0xff; - register_HDMA3 = gbHdmaDestination>>8; + register_HDMA4 = gbHdmaDestination & 0xff; + register_HDMA3 = gbHdmaDestination >> 8; - gbHdmaBytes -= 0x10; - gbMemory[0xff55] = --register_HDMA5; - if(register_HDMA5 == 0xff) - gbHdmaOn = 0; + gbHdmaBytes -= 0x10; + gbMemory[0xff55] = --register_HDMA5; + if (register_HDMA5 == 0xff) + gbHdmaOn = 0; -// We need to add the dmaClockticks for HDMA ! - if(gbSpeed) - gbDmaTicks = 17; - else - gbDmaTicks = 9; - - if (IFF & 0x80) - gbDmaTicks++; + // We need to add the dmaClockticks for HDMA ! + if (gbSpeed) + gbDmaTicks = 17; + else + gbDmaTicks = 9; + if (IFF & 0x80) + gbDmaTicks++; } // fix for Harley and Lego Racers void gbCompareLYToLYC() { - if(register_LCDC & 0x80) { - if(register_LY == register_LYC) { + if (register_LCDC & 0x80) { + if (register_LY == register_LYC) { - // mark that we have a match - register_STAT |= 4; + // mark that we have a match + register_STAT |= 4; - // check if we need an interrupt - if (register_STAT & 0x40) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!gbInt48Signal) + // check if we need an interrupt + if (register_STAT & 0x40) { + // send LCD interrupt only if no interrupt 48h signal... + if (!gbInt48Signal) { + register_IF |= 2; + } + gbInt48Signal |= 8; + } + } else // no match { - register_IF |=2; + register_STAT &= 0xfb; + gbInt48Signal &= ~8; } - gbInt48Signal |= 8; - } } - else // no match - { - register_STAT &= 0xfb; - gbInt48Signal &=~8; - } - } } -void gbWriteMemory(register uint16_t address, register uint8_t value) +void gbWriteMemory(register uint16_t address, register uint8_t value) { - if(address < 0x8000) { + if (address < 0x8000) { #ifndef FINAL_VERSION - if(memorydebug && (address>0x3fff || address < 0x2000)) { - log("Memory register write %04x=%02x PC=%04x\n", - address, - value, - PC.W); - } + 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) { - // No access to Vram during mode 3 - // (used to emulate the gfx differences between GB & GBC-GBA/SP in Stunt Racer) - if ((gbLcdModeDelayed !=3) || - // This part is used to emulate a small difference between hardwares - // (check 8-in-1's arrow on GBA/GBC to verify it) - ((register_LY == 0) && ((gbHardware & 0xa) && (gbScreenOn==false) && - (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicksDelayed ==(GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS)))) - gbMemoryMap[address>>12][address&0x0fff] = value; - return; - } - - // Used for the mirroring of 0xC000 in 0xE000 - if ((address >= 0xe000) && (address < 0xfe00)) - address &= ~0x2000; - - if(address < 0xc000) { -#ifndef FINAL_VERSION - if(memorydebug) { - log("Memory register write %04x=%02x PC=%04x\n", - address, - value, - PC.W); + if (mapper) + (*mapper)(address, value); + return; } + + if (address < 0xa000) { + // No access to Vram during mode 3 + // (used to emulate the gfx differences between GB & GBC-GBA/SP in Stunt Racer) + if ((gbLcdModeDelayed != 3) || + // This part is used to emulate a small difference between hardwares + // (check 8-in-1's arrow on GBA/GBC to verify it) + ((register_LY == 0) && ((gbHardware & 0xa) && (gbScreenOn == false) && (register_LCDC & 0x80)) && (gbLcdLYIncrementTicksDelayed == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS)))) + gbMemoryMap[address >> 12][address & 0x0fff] = value; + return; + } + + // Used for the mirroring of 0xC000 in 0xE000 + if ((address >= 0xe000) && (address < 0xfe00)) + address &= ~0x2000; + + if (address < 0xc000) { +#ifndef FINAL_VERSION + if (memorydebug) { + log("Memory register write %04x=%02x PC=%04x\n", + address, + value, + PC.W); + } #endif - // Is that a correct fix ??? (it used to be 'if (mapper)')... - if(mapperRAM) - (*mapperRAM)(address, value); - return; - } - - - if(address < 0xfe00) { - gbMemoryMap[address>>12][address & 0x0fff] = value; - return; - } - - // OAM not accessible during mode 2 & 3. - if(address < 0xfea0) - { - if (((gbHardware & 0xa) && ((gbLcdMode | gbLcdModeDelayed) &2)) || - ((gbHardware & 5) && (((gbLcdModeDelayed == 2) && - (gbLcdTicksDelayed<=GBLCD_MODE_2_CLOCK_TICKS)) || - (gbLcdModeDelayed == 3)))) - return; - else - { - gbMemory[address] = value; - return; + // Is that a correct fix ??? (it used to be 'if (mapper)')... + if (mapperRAM) + (*mapperRAM)(address, value); + return; } - } + if (address < 0xfe00) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + return; + } + // OAM not accessible during mode 2 & 3. + if (address < 0xfea0) { + if (((gbHardware & 0xa) && ((gbLcdMode | gbLcdModeDelayed) & 2)) || ((gbHardware & 5) && (((gbLcdModeDelayed == 2) && (gbLcdTicksDelayed <= GBLCD_MODE_2_CLOCK_TICKS)) || (gbLcdModeDelayed == 3)))) + return; + else { + gbMemory[address] = value; + return; + } + } - if((address > 0xfea0) && (address < 0xff00)){ // GBC allows reading/writing to that area - gbMemory[address] = value; - return; - } + if ((address > 0xfea0) && (address < 0xff00)) { // GBC allows reading/writing to that area + gbMemory[address] = value; + return; + } - switch(address & 0x00ff) { + switch (address & 0x00ff) { case 0x00: { - gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | - (value & 0x30) | 0xc0); - if(gbSgbMode) { - gbSgbDoBitTransfer(value); - } - return; + gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | (value & 0x30) | 0xc0); + if (gbSgbMode) { + gbSgbDoBitTransfer(value); + } + return; } case 0x01: { - gbMemory[0xff01] = value; - return; + gbMemory[0xff01] = value; + return; } - // serial control - case 0x02: { - gbSerialOn = (value & 0x80); + // serial control + case 0x02: { + gbSerialOn = (value & 0x80); #ifndef NO_LINK - //trying to detect whether the game has exited multiplay mode, pokemon blue start w/ 0x7e while pocket racing start w/ 0x7c - if (EmuReseted || (gbMemory[0xff02] & 0x7c) || (value & 0x7c) || (!(value & 0x81))) { - LinkFirstTime = true; - } - EmuReseted = false; - gbMemory[0xff02] = value; - if (gbSerialOn && (GetLinkMode() == LINK_GAMEBOY_IPC || GetLinkMode() == LINK_GAMEBOY_SOCKET || winGbPrinterEnabled)) { - gbSerialTicks = GBSERIAL_CLOCK_TICKS; + //trying to detect whether the game has exited multiplay mode, pokemon blue start w/ 0x7e while pocket racing start w/ 0x7c + if (EmuReseted || (gbMemory[0xff02] & 0x7c) || (value & 0x7c) || (!(value & 0x81))) { + LinkFirstTime = true; + } + EmuReseted = false; + gbMemory[0xff02] = value; + if (gbSerialOn && (GetLinkMode() == LINK_GAMEBOY_IPC || GetLinkMode() == LINK_GAMEBOY_SOCKET || winGbPrinterEnabled)) { + gbSerialTicks = GBSERIAL_CLOCK_TICKS; - LinkIsWaiting = true; + LinkIsWaiting = true; - //Do data exchange, master initiate the transfer - //may cause visual artifact if not processed immediately, is it due to IRQ stuff or invalid data being exchanged? - if ((value & 1) ) { //internal clock - if (gbSerialFunction) { - gbSIO_SC = value; - gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); //gbSerialFunction/gbStartLink/gbPrinter - } - else gbMemory[0xff01] = 0xff; - gbMemory[0xff02] &= 0x7f; - gbSerialOn = 0; - gbMemory[0xff0f] = register_IF |= 8; - } + //Do data exchange, master initiate the transfer + //may cause visual artifact if not processed immediately, is it due to IRQ stuff or invalid data being exchanged? + if ((value & 1)) { //internal clock + if (gbSerialFunction) { + gbSIO_SC = value; + gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); //gbSerialFunction/gbStartLink/gbPrinter + } else + gbMemory[0xff01] = 0xff; + gbMemory[0xff02] &= 0x7f; + gbSerialOn = 0; + gbMemory[0xff0f] = register_IF |= 8; + } #ifdef OLD_GB_LINK - if (linkConnected) { - if (value & 1) { - linkSendByte(0x100 | gbMemory[0xFF01]); - Sleep(5); - } - } + if (linkConnected) { + if (value & 1) { + linkSendByte(0x100 | gbMemory[0xFF01]); + Sleep(5); + } + } #endif - } + } - gbSerialBits = 0; - return; + gbSerialBits = 0; + return; #endif - } + } case 0x04: { - // DIV register resets on any write - // (not totally perfect, but better than nothing) - gbMemory[0xff04] = register_DIV = 0; - gbDivTicks = GBDIV_CLOCK_TICKS; - // Another weird timer 'bug' : - // Writing to DIV register resets the internal timer, - // and can also increase TIMA/trigger an interrupt - // in some cases... - if (gbTimerOn && !(gbInternalTimer & (gbTimerClockTicks>>1))) - { - gbMemory[0xff05] = ++register_TIMA; - if(register_TIMA == 0) { - // timer overflow! + // DIV register resets on any write + // (not totally perfect, but better than nothing) + gbMemory[0xff04] = register_DIV = 0; + gbDivTicks = GBDIV_CLOCK_TICKS; + // Another weird timer 'bug' : + // Writing to DIV register resets the internal timer, + // and can also increase TIMA/trigger an interrupt + // in some cases... + if (gbTimerOn && !(gbInternalTimer & (gbTimerClockTicks >> 1))) { + gbMemory[0xff05] = ++register_TIMA; + if (register_TIMA == 0) { + // timer overflow! - // reload timer modulo - gbMemory[0xff05] = register_TIMA = register_TMA; + // reload timer modulo + gbMemory[0xff05] = register_TIMA = register_TMA; - // flag interrupt - gbMemory[0xff0f] = register_IF |= 4; + // flag interrupt + gbMemory[0xff0f] = register_IF |= 4; + } } - } - gbInternalTimer = 0xff; - return; + gbInternalTimer = 0xff; + return; } case 0x05: - gbMemory[0xff05] = register_TIMA = value; - return; + gbMemory[0xff05] = register_TIMA = value; + return; case 0x06: - gbMemory[0xff06] = register_TMA = value; - return; + gbMemory[0xff06] = register_TMA = value; + return; - // TIMER control + // TIMER control case 0x07: { - gbTimerModeChange = (((value & 3) != (register_TAC&3)) && (value & register_TAC & 4)) ? true : false; - gbTimerOnChange = (((value ^ register_TAC) & 4) == 4) ? true : false; + gbTimerModeChange = (((value & 3) != (register_TAC & 3)) && (value & register_TAC & 4)) ? true : false; + gbTimerOnChange = (((value ^ register_TAC) & 4) == 4) ? true : false; - gbTimerOn = (value & 4) ? true : false; + gbTimerOn = (value & 4) ? true : false; - if (gbTimerOnChange || gbTimerModeChange) - { - gbTimerMode = value & 3; + if (gbTimerOnChange || gbTimerModeChange) { + gbTimerMode = value & 3; - switch(gbTimerMode) { - case 0: - gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; - break; - case 1: - gbTimerClockTicks = GBTIMER_MODE_1_CLOCK_TICKS; - break; - case 2: - gbTimerClockTicks = GBTIMER_MODE_2_CLOCK_TICKS; - break; - case 3: - gbTimerClockTicks = GBTIMER_MODE_3_CLOCK_TICKS; - break; - } - } - - - // This looks weird, but this emulates a bug in which register_TIMA - // is increased when writing to register_TAC - // (This fixes Korodice's long-delay between menus bug). - - if (gbTimerOnChange || gbTimerModeChange) - { - bool temp = false; - - if ((gbTimerOn && !gbTimerModeChange) && (gbTimerMode & 2) && - !(gbInternalTimer & 0x80) && (gbInternalTimer & (gbTimerClockTicks>>1)) && - !(gbInternalTimer & (gbTimerClockTicks>>5))) - temp = true; - else if ((!gbTimerOn && !gbTimerModeChange && gbTimerOnChange ) && ((gbTimerTicks-1) < (gbTimerClockTicks>>1))) - temp = true; - else if (gbTimerOn && gbTimerModeChange && !gbTimerOnChange) - { - switch(gbTimerMode & 3) - { - case 0x00: - temp = false; - break; - case 0x01: - if (((gbInternalTimer & 0x82) == 2) && (gbTimerTicks>(clockTicks+1))) - temp = true; - break; - case 0x02: - if (((gbInternalTimer & 0x88) == 0x8) && (gbTimerTicks>(clockTicks+1))) - temp = true; - break; - case 0x03: - if (((gbInternalTimer & 0xA0) == 0x20) && (gbTimerTicks>(clockTicks+1))) - temp = true; - break; - } + switch (gbTimerMode) { + case 0: + gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; + break; + case 1: + gbTimerClockTicks = GBTIMER_MODE_1_CLOCK_TICKS; + break; + case 2: + gbTimerClockTicks = GBTIMER_MODE_2_CLOCK_TICKS; + break; + case 3: + gbTimerClockTicks = GBTIMER_MODE_3_CLOCK_TICKS; + break; + } } - if (temp) - { - gbMemory[0xff05] = ++register_TIMA; - if((register_TIMA & 0xff) == 0) { - // timer overflow! + // This looks weird, but this emulates a bug in which register_TIMA + // is increased when writing to register_TAC + // (This fixes Korodice's long-delay between menus bug). - // reload timer modulo - gbMemory[0xff05] = register_TIMA = register_TMA; + if (gbTimerOnChange || gbTimerModeChange) { + bool temp = false; - // flag interrupt - gbMemory[0xff0f] = register_IF |= 4; - } + if ((gbTimerOn && !gbTimerModeChange) && (gbTimerMode & 2) && !(gbInternalTimer & 0x80) && (gbInternalTimer & (gbTimerClockTicks >> 1)) && !(gbInternalTimer & (gbTimerClockTicks >> 5))) + temp = true; + else if ((!gbTimerOn && !gbTimerModeChange && gbTimerOnChange) && ((gbTimerTicks - 1) < (gbTimerClockTicks >> 1))) + temp = true; + else if (gbTimerOn && gbTimerModeChange && !gbTimerOnChange) { + switch (gbTimerMode & 3) { + case 0x00: + temp = false; + break; + case 0x01: + if (((gbInternalTimer & 0x82) == 2) && (gbTimerTicks > (clockTicks + 1))) + temp = true; + break; + case 0x02: + if (((gbInternalTimer & 0x88) == 0x8) && (gbTimerTicks > (clockTicks + 1))) + temp = true; + break; + case 0x03: + if (((gbInternalTimer & 0xA0) == 0x20) && (gbTimerTicks > (clockTicks + 1))) + temp = true; + break; + } + } + + if (temp) { + gbMemory[0xff05] = ++register_TIMA; + if ((register_TIMA & 0xff) == 0) { + // timer overflow! + + // reload timer modulo + gbMemory[0xff05] = register_TIMA = register_TMA; + + // flag interrupt + gbMemory[0xff0f] = register_IF |= 4; + } + } } - } - gbMemory[0xff07] = register_TAC = value; - return; + gbMemory[0xff07] = register_TAC = value; + return; } case 0x0f: { - gbMemory[0xff0f] = register_IF = value; - //gbMemory[0xff0f] = register_IE |= value; - return; + gbMemory[0xff0f] = register_IF = value; + //gbMemory[0xff0f] = register_IE |= value; + return; } case 0x10: @@ -1180,15 +1157,15 @@ void gbWriteMemory(register uint16_t address, register uint8_t value) case 0x23: case 0x24: case 0x25: { - if (gbMemory[NR52] & 0x80) { - SOUND_EVENT(address,value); - return; - } + if (gbMemory[NR52] & 0x80) { + SOUND_EVENT(address, value); + return; + } } case 0x26: { - SOUND_EVENT(address,value); - return; + SOUND_EVENT(address, value); + return; } case 0x30: @@ -1207,1834 +1184,2700 @@ void gbWriteMemory(register uint16_t address, register uint8_t value) case 0x3d: case 0x3e: case 0x3f: { - SOUND_EVENT(address,value); - //gbMemory[address] = value; - return; + SOUND_EVENT(address, value); + //gbMemory[address] = value; + return; } case 0x40: { - int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); + int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); - // 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 = 146; - // 007 fix : don't draw the first window's 1st line if it's enable 'too late' - // (ie. if register_LY == register_WY when enabling it) - // and move it to the next line - else if (!(register_LCDC & 0x20) && (value & 0x20) && (register_LY == register_WY)) - gbWindowLine = -2; + // 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 = 146; + // 007 fix : don't draw the first window's 1st line if it's enable 'too late' + // (ie. if register_LY == register_WY when enabling it) + // and move it to the next line + else if (!(register_LCDC & 0x20) && (value & 0x20) && (register_LY == register_WY)) + gbWindowLine = -2; + gbMemory[0xff40] = register_LCDC = value; - gbMemory[0xff40] = register_LCDC = value; + if (lcdChange) { + if ((value & 0x80) && (!register_LCDCBusy)) { + // if (!gbWhiteScreen && !gbSgbMask) - if(lcdChange) { - if((value & 0x80) && (!register_LCDCBusy)) { + // systemDrawScreen(); - // if (!gbWhiteScreen && !gbSgbMask) + gbRegisterLYLCDCOffOn = (register_LY + 144) % 154; - // systemDrawScreen(); + gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 2 : 1); + gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 1 : 0); + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS - (gbSpeed ? 2 : 1); + gbLcdLYIncrementTicksDelayed = GBLY_INCREMENT_CLOCK_TICKS - (gbSpeed ? 1 : 0); + gbLcdMode = 2; + gbLcdModeDelayed = 2; + gbMemory[0xff41] = register_STAT = (register_STAT & 0xfc) | 2; + gbMemory[0xff44] = register_LY = 0x00; + gbInt48Signal = 0; + gbLYChangeHappened = false; + gbLCDChangeHappened = false; + gbWindowLine = 146; + oldRegister_WY = 146; + // Fix for Namco Gallery Vol.2 + // (along with updating register_LCDC at the start of 'case 0x40') : + if (register_STAT & 0x20) { + // send LCD interrupt only if no interrupt 48h signal... + if (!gbInt48Signal) { + gbMemory[0xff0f] = register_IF |= 2; + } + gbInt48Signal |= 4; + } + gbCompareLYToLYC(); + } else { - gbRegisterLYLCDCOffOn = (register_LY + 144) % 154; + register_LCDCBusy = clockTicks + 6; - gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 2 : 1); - gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 1 : 0); - gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS - (gbSpeed ? 2 : 1); - gbLcdLYIncrementTicksDelayed = GBLY_INCREMENT_CLOCK_TICKS - (gbSpeed ? 1 : 0); - gbLcdMode = 2; - gbLcdModeDelayed = 2; - gbMemory[0xff41] = register_STAT = (register_STAT & 0xfc) | 2; - gbMemory[0xff44] = register_LY = 0x00; - gbInt48Signal = 0; - gbLYChangeHappened = false; - gbLCDChangeHappened = false; - gbWindowLine = 146; - oldRegister_WY = 146; + //used to update the screen with white lines when it's off. + //(it looks strange, but it's pretty accurate) - // Fix for Namco Gallery Vol.2 - // (along with updating register_LCDC at the start of 'case 0x40') : - if(register_STAT & 0x20) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!gbInt48Signal) - { - gbMemory[0xff0f] = register_IF |= 2; + gbWhiteScreen = 0; + + gbScreenTicks = ((150 - register_LY) * GBLY_INCREMENT_CLOCK_TICKS + (49 << (gbSpeed ? 1 : 0))); + + // disable the screen rendering + gbScreenOn = false; + gbLcdTicks = 0; + gbLcdMode = 0; + gbLcdModeDelayed = 0; + gbMemory[0xff41] = register_STAT &= 0xfc; + gbInt48Signal = 0; } - gbInt48Signal |= 4; - } - gbCompareLYToLYC(); - - } else { - - register_LCDCBusy = clockTicks+6; - - //used to update the screen with white lines when it's off. - //(it looks strange, but it's pretty accurate) - - gbWhiteScreen = 0; - - gbScreenTicks = ((150-register_LY)*GBLY_INCREMENT_CLOCK_TICKS + - (49<<(gbSpeed ? 1 : 0))); - - // disable the screen rendering - gbScreenOn = false; - gbLcdTicks = 0; - gbLcdMode = 0; - gbLcdModeDelayed = 0; - gbMemory[0xff41] = register_STAT &= 0xfc; - gbInt48Signal = 0; } - } - return; + return; } // STAT case 0x41: { - //register_STAT = (register_STAT & 0x87) | - // (value & 0x7c); - gbMemory[0xff41] = register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? - // GB bug from Devrs FAQ - // proper fix - gbInt48Signal &= ((register_STAT>>3) & 0xF); + //register_STAT = (register_STAT & 0x87) | + // (value & 0x7c); + gbMemory[0xff41] = register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? + // GB bug from Devrs FAQ + // proper fix + gbInt48Signal &= ((register_STAT >> 3) & 0xF); - if((register_LCDC & 0x80)) { - if ((register_STAT & 0x08) && (gbLcdMode == 0)) - { - if (!gbInt48Signal) - { - gbMemory[0xff0f] = register_IF |=2; - } - gbInt48Signal |= 1; - } - if ((register_STAT & 0x10) && (gbLcdMode == 1)) - { - if (!gbInt48Signal) - { - gbMemory[0xff0f] = register_IF |=2; - } - gbInt48Signal |= 2; - } - if ((register_STAT & 0x20) && (gbLcdMode == 2)) - { - if (!gbInt48Signal) - { - gbMemory[0xff0f] = register_IF |=2; - } - gbInt48Signal |= 4; - } - gbCompareLYToLYC(); + if ((register_LCDC & 0x80)) { + if ((register_STAT & 0x08) && (gbLcdMode == 0)) { + if (!gbInt48Signal) { + gbMemory[0xff0f] = register_IF |= 2; + } + gbInt48Signal |= 1; + } + if ((register_STAT & 0x10) && (gbLcdMode == 1)) { + if (!gbInt48Signal) { + gbMemory[0xff0f] = register_IF |= 2; + } + gbInt48Signal |= 2; + } + if ((register_STAT & 0x20) && (gbLcdMode == 2)) { + if (!gbInt48Signal) { + gbMemory[0xff0f] = register_IF |= 2; + } + gbInt48Signal |= 4; + } + gbCompareLYToLYC(); - gbMemory[0xff0f] = register_IF; - gbMemory[0xff41] = register_STAT; - - } - return; + gbMemory[0xff0f] = register_IF; + gbMemory[0xff41] = register_STAT; + } + return; } // SCY case 0x42: { - int temp = -1; + int temp = -1; - if ((gbLcdMode == 3) || (gbLcdModeDelayed == 3)) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicks); + if ((gbLcdMode == 3) || (gbLcdModeDelayed == 3)) + temp = ((GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS) - gbLcdLYIncrementTicks); - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbSCYLine[i] = value; - } + if (temp >= 0) { + for (int i = temp << (gbSpeed ? 1 : 2); i < 300; i++) + if (temp < 300) + gbSCYLine[i] = value; + } - else - memset(gbSCYLine, value, sizeof(gbSCYLine)); + else + memset(gbSCYLine, value, sizeof(gbSCYLine)); - gbMemory[0xff42] = register_SCY = value; - return; + gbMemory[0xff42] = register_SCY = value; + return; } // SCX case 0x43: { - int temp = -1; + int temp = -1; - if (gbLcdModeDelayed == 3) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicksDelayed); + if (gbLcdModeDelayed == 3) + temp = ((GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS) - gbLcdLYIncrementTicksDelayed); - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbSCXLine[i] = value; - } + if (temp >= 0) { + for (int i = temp << (gbSpeed ? 1 : 2); i < 300; i++) + if (temp < 300) + gbSCXLine[i] = value; + } - else - memset(gbSCXLine, value, sizeof(gbSCXLine)); + else + memset(gbSCXLine, value, sizeof(gbSCXLine)); - gbMemory[0xff43] = register_SCX = value; - return; + gbMemory[0xff43] = register_SCX = value; + return; } // LY case 0x44: { - // read only - return; + // read only + return; } // LYC case 0x45: { - if (register_LYC != value) - { - gbMemory[0xff45] = register_LYC = value; - if(register_LCDC & 0x80) { - gbCompareLYToLYC(); + if (register_LYC != value) { + gbMemory[0xff45] = register_LYC = value; + if (register_LCDC & 0x80) { + gbCompareLYToLYC(); + } } - } - return; + return; } // DMA! case 0x46: { - int source = value * 0x0100; + int source = value * 0x0100; - gbCopyMemory(0xfe00, - source, - 0xa0); - gbMemory[0xff46] = register_DMA = value; - return; + gbCopyMemory(0xfe00, + source, + 0xa0); + gbMemory[0xff46] = register_DMA = value; + return; } // BGP case 0x47: { - int temp = -1; + int temp = -1; - gbMemory[0xff47] = value; + gbMemory[0xff47] = value; - if (gbLcdModeDelayed == 3) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicksDelayed); + if (gbLcdModeDelayed == 3) + temp = ((GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS) - gbLcdLYIncrementTicksDelayed); - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbBgpLine[i] = value; - } - else - memset(gbBgpLine,value,sizeof(gbBgpLine)); + if (temp >= 0) { + for (int i = temp << (gbSpeed ? 1 : 2); i < 300; i++) + if (temp < 300) + gbBgpLine[i] = value; + } else + memset(gbBgpLine, value, sizeof(gbBgpLine)); - gbBgp[0] = value & 0x03; - gbBgp[1] = (value & 0x0c)>>2; - gbBgp[2] = (value & 0x30)>>4; - gbBgp[3] = (value & 0xc0)>>6; - break; + gbBgp[0] = value & 0x03; + gbBgp[1] = (value & 0x0c) >> 2; + gbBgp[2] = (value & 0x30) >> 4; + gbBgp[3] = (value & 0xc0) >> 6; + break; } // OBP0 case 0x48: { - int temp = -1; + int temp = -1; - gbMemory[0xff48] = value; + gbMemory[0xff48] = value; - if (gbLcdModeDelayed == 3) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicksDelayed); + if (gbLcdModeDelayed == 3) + temp = ((GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS) - gbLcdLYIncrementTicksDelayed); - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbObp0Line[i] = value; - } - else - memset(gbObp0Line,value,sizeof(gbObp0Line)); + if (temp >= 0) { + for (int i = temp << (gbSpeed ? 1 : 2); i < 300; i++) + if (temp < 300) + gbObp0Line[i] = value; + } else + memset(gbObp0Line, value, sizeof(gbObp0Line)); - gbObp0[0] = value & 0x03; - gbObp0[1] = (value & 0x0c)>>2; - gbObp0[2] = (value & 0x30)>>4; - gbObp0[3] = (value & 0xc0)>>6; - break; + gbObp0[0] = value & 0x03; + gbObp0[1] = (value & 0x0c) >> 2; + gbObp0[2] = (value & 0x30) >> 4; + gbObp0[3] = (value & 0xc0) >> 6; + break; } // OBP1 case 0x49: { - int temp = -1; + int temp = -1; - gbMemory[0xff49] = value; + gbMemory[0xff49] = value; - if (gbLcdModeDelayed == 3) - temp = ((GBLY_INCREMENT_CLOCK_TICKS-GBLCD_MODE_2_CLOCK_TICKS) - - gbLcdLYIncrementTicksDelayed); + if (gbLcdModeDelayed == 3) + temp = ((GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS) - gbLcdLYIncrementTicksDelayed); - if (temp >=0) - { - for (int i=temp<<(gbSpeed ? 1 : 2);i<300;i++) - if (temp < 300) - gbObp1Line[i] = value; - } - else - memset(gbObp1Line,value,sizeof(gbObp1Line)); + if (temp >= 0) { + for (int i = temp << (gbSpeed ? 1 : 2); i < 300; i++) + if (temp < 300) + gbObp1Line[i] = value; + } else + memset(gbObp1Line, value, sizeof(gbObp1Line)); - gbObp1[0] = value & 0x03; - gbObp1[1] = (value & 0x0c)>>2; - gbObp1[2] = (value & 0x30)>>4; - gbObp1[3] = (value & 0xc0)>>6; - break; + gbObp1[0] = value & 0x03; + gbObp1[1] = (value & 0x0c) >> 2; + gbObp1[2] = (value & 0x30) >> 4; + gbObp1[3] = (value & 0xc0) >> 6; + break; } // WY case 0x4a: - gbMemory[0xff4a] = register_WY = value; - if ((register_LY <= register_WY) && ((gbWindowLine < 0) || (gbWindowLine>=144))) - { - gbWindowLine = -1; - oldRegister_WY = register_WY; - } - return; + gbMemory[0xff4a] = register_WY = value; + if ((register_LY <= register_WY) && ((gbWindowLine < 0) || (gbWindowLine >= 144))) { + gbWindowLine = -1; + oldRegister_WY = register_WY; + } + return; // WX case 0x4b: - gbMemory[0xff4b] = register_WX = value; - return; + gbMemory[0xff4b] = register_WX = value; + return; // KEY1 case 0x4d: { - if(gbCgbMode) { - gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1) | 0x7e; - return; - } - } - break; + if (gbCgbMode) { + gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1) | 0x7e; + return; + } + } break; // VBK case 0x4f: { - if(gbCgbMode) { - value = value & 1; - if(value == gbVramBank) - return; + if (gbCgbMode) { + value = value & 1; + if (value == gbVramBank) + return; - int vramAddress = value * 0x2000; - gbMemoryMap[0x08] = &gbVram[vramAddress]; - gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; + int vramAddress = value * 0x2000; + gbMemoryMap[0x08] = &gbVram[vramAddress]; + gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; - gbVramBank = value; - register_VBK = value; - } - return; - } - break; + gbVramBank = value; + register_VBK = value; + } + return; + } break; // BOOTROM disable register (also gbCgbMode enabler if value & 0x10 ?) - case 0x50 : - { - if (inBios && (value & 1)) - { - gbMemoryMap[0x00] = &gbRom[0x0000]; - if (gbHardware & 5) { - memcpy ((uint8_t *)(gbRom+0x100), (uint8_t *)(gbMemory + 0x100), 0xF00); + case 0x50: { + if (inBios && (value & 1)) { + gbMemoryMap[0x00] = &gbRom[0x0000]; + if (gbHardware & 5) { + memcpy((uint8_t*)(gbRom + 0x100), (uint8_t*)(gbMemory + 0x100), 0xF00); + } + inBios = false; } - inBios = false; - } } // HDMA1 case 0x51: { - if(gbCgbMode) { - if(value > 0x7f && value < 0xa0) - value = 0; + if (gbCgbMode) { + if (value > 0x7f && value < 0xa0) + value = 0; - gbHdmaSource = (value << 8) | (gbHdmaSource & 0xf0); + gbHdmaSource = (value << 8) | (gbHdmaSource & 0xf0); - register_HDMA1 = value; - return; - } - } - break; + register_HDMA1 = value; + return; + } + } break; // HDMA2 case 0x52: { - if(gbCgbMode) { - value = value & 0xf0; + if (gbCgbMode) { + value = value & 0xf0; - gbHdmaSource = (gbHdmaSource & 0xff00) | (value); + gbHdmaSource = (gbHdmaSource & 0xff00) | (value); - register_HDMA2 = value; - return; - } - } - break; + register_HDMA2 = value; + return; + } + } break; // HDMA3 case 0x53: { - if(gbCgbMode) { - value = value & 0x1f; - gbHdmaDestination = (value << 8) | (gbHdmaDestination & 0xf0); - gbHdmaDestination |= 0x8000; - register_HDMA3 = value; - return; - } - } - break; + if (gbCgbMode) { + value = value & 0x1f; + gbHdmaDestination = (value << 8) | (gbHdmaDestination & 0xf0); + gbHdmaDestination |= 0x8000; + register_HDMA3 = value; + return; + } + } break; // HDMA4 case 0x54: { - if(gbCgbMode) { - value = value & 0xf0; - gbHdmaDestination = (gbHdmaDestination & 0x1f00) | value; - gbHdmaDestination |= 0x8000; - register_HDMA4 = value; - return; - } - } - break; + if (gbCgbMode) { + value = value & 0xf0; + gbHdmaDestination = (gbHdmaDestination & 0x1f00) | value; + gbHdmaDestination |= 0x8000; + register_HDMA4 = value; + return; + } + } break; // HDMA5 case 0x55: { - if(gbCgbMode) { - gbHdmaBytes = 16 + (value & 0x7f) * 16; - if(gbHdmaOn) { - if(value & 0x80) { - gbMemory[0xff55] = register_HDMA5 = (value & 0x7f); - } else { - register_HDMA5 = 0xff; - gbHdmaOn = 0; - } - } else { - if(value & 0x80) { - gbHdmaOn = 1; - gbMemory[0xff55] = register_HDMA5 = value & 0x7f; - if(gbLcdModeDelayed == 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 - if(gbSpeed) - gbDmaTicks = 2+16 * ((value & 0x7f) +1); - else - gbDmaTicks = 1+8 * ((value & 0x7f)+1); + if (gbCgbMode) { + gbHdmaBytes = 16 + (value & 0x7f) * 16; + if (gbHdmaOn) { + if (value & 0x80) { + gbMemory[0xff55] = register_HDMA5 = (value & 0x7f); + } else { + register_HDMA5 = 0xff; + gbHdmaOn = 0; + } + } else { + if (value & 0x80) { + gbHdmaOn = 1; + gbMemory[0xff55] = register_HDMA5 = value & 0x7f; + if (gbLcdModeDelayed == 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 + if (gbSpeed) + gbDmaTicks = 2 + 16 * ((value & 0x7f) + 1); + else + gbDmaTicks = 1 + 8 * ((value & 0x7f) + 1); - gbCopyMemory((gbHdmaDestination & 0x1ff0) | 0x8000, - gbHdmaSource & 0xfff0, - gbHdmaBytes); - gbHdmaDestination += gbHdmaBytes; - gbHdmaSource += gbHdmaBytes; + gbCopyMemory((gbHdmaDestination & 0x1ff0) | 0x8000, + gbHdmaSource & 0xfff0, + gbHdmaBytes); + gbHdmaDestination += gbHdmaBytes; + gbHdmaSource += gbHdmaBytes; - gbMemory[0xff51] = register_HDMA1 = 0xff;// = (gbHdmaSource >> 8) & 0xff; - gbMemory[0xff52] = register_HDMA2 = 0xff;// = gbHdmaSource & 0xf0; - gbMemory[0xff53] = register_HDMA3 = 0xff;// = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; - gbMemory[0xff54] = register_HDMA4 = 0xff;// = gbHdmaDestination & 0xf0; - gbMemory[0xff55] = register_HDMA5 = 0xff; - } + gbMemory[0xff51] = register_HDMA1 = 0xff; // = (gbHdmaSource >> 8) & 0xff; + gbMemory[0xff52] = register_HDMA2 = 0xff; // = gbHdmaSource & 0xf0; + gbMemory[0xff53] = register_HDMA3 = 0xff; // = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; + gbMemory[0xff54] = register_HDMA4 = 0xff; // = gbHdmaDestination & 0xf0; + gbMemory[0xff55] = register_HDMA5 = 0xff; + } + } + return; } - return; - } - } - break; + } break; // BCPS case 0x68: { - if(gbCgbMode) { - int paletteIndex = (value & 0x3f) >> 1; - int paletteHiLo = (value & 0x01); + if (gbCgbMode) { + int paletteIndex = (value & 0x3f) >> 1; + int paletteHiLo = (value & 0x01); - gbMemory[0xff68] = value; + gbMemory[0xff68] = value; - gbMemory[0xff69] = (paletteHiLo ? - (gbPalette[paletteIndex] >> 8) : - (gbPalette[paletteIndex] & 0x00ff)); - return; - } - } - break; + 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); + if (gbCgbMode) { + int v = gbMemory[0xff68]; + int paletteIndex = (v & 0x3f) >> 1; + int paletteHiLo = (v & 0x01); - // No access to gbPalette during mode 3 (Color Panel Demo) - if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || - (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || - ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || - ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) - { - gbMemory[0xff69] = value; - gbPalette[paletteIndex] = (paletteHiLo ? - ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : - ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; + // No access to gbPalette during mode 3 (Color Panel Demo) + if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks >= (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299] - 1)))) && (!gbSpeed)) || (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || ((gbLcdMode == 3) && (gbLcdTicks > (GBLCD_MODE_3_CLOCK_TICKS - 2))) || ((gbLcdMode == 0) && (gbLcdTicks <= (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299] - 2)))))) { + 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; } - - - 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; + } break; // OCPS case 0x6a: { - if(gbCgbMode) { - int paletteIndex = (value & 0x3f) >> 1; - int paletteHiLo = (value & 0x01); + if (gbCgbMode) { + int paletteIndex = (value & 0x3f) >> 1; + int paletteHiLo = (value & 0x01); - paletteIndex += 32; + paletteIndex += 32; - gbMemory[0xff6a] = value; + gbMemory[0xff6a] = value; - gbMemory[0xff6b] = (paletteHiLo ? - (gbPalette[paletteIndex] >> 8) : - (gbPalette[paletteIndex] & 0x00ff)); - return; - } - } - break; + 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); + if (gbCgbMode) { + int v = gbMemory[0xff6a]; + int paletteIndex = (v & 0x3f) >> 1; + int paletteHiLo = (v & 0x01); - paletteIndex += 32; + paletteIndex += 32; - // No access to gbPalette during mode 3 (Color Panel Demo) - if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || - (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || - ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || - ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) - { - gbMemory[0xff6b] = value; - gbPalette[paletteIndex] = (paletteHiLo ? - ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : - ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; + // No access to gbPalette during mode 3 (Color Panel Demo) + if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks >= (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299] - 1)))) && (!gbSpeed)) || (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || ((gbLcdMode == 3) && (gbLcdTicks > (GBLCD_MODE_3_CLOCK_TICKS - 2))) || ((gbLcdMode == 0) && (gbLcdTicks <= (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299] - 2)))))) { + 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; } - - 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; + } break; case 0x6c: { - gbMemory[0xff6c] = 0xfe | value; - return; + gbMemory[0xff6c] = 0xfe | value; + return; } - // SVBK case 0x70: { - if(gbCgbMode) { - value = value & 7; + if (gbCgbMode) { + value = value & 7; - int bank = value; - if(value == 0) - bank = 1; + int bank = value; + if (value == 0) + bank = 1; - if(bank == gbWramBank) - return; + if (bank == gbWramBank) + return; - int wramAddress = bank * 0x1000; - gbMemoryMap[0x0d] = &gbWram[wramAddress]; + int wramAddress = bank * 0x1000; + gbMemoryMap[0x0d] = &gbWram[wramAddress]; - gbWramBank = bank; - gbMemory[0xff70] = register_SVBK = value; - return; - } + gbWramBank = bank; + gbMemory[0xff70] = register_SVBK = value; + return; + } } - case 0x75:{ - gbMemory[0xff75] = 0x8f | value; - return; + case 0x75: { + gbMemory[0xff75] = 0x8f | value; + return; } case 0xff: { - gbMemory[0xffff] = register_IE = value; - return; + gbMemory[0xffff] = register_IE = value; + return; + } + } + + if (address < 0xff80) { + gbMemory[address] = value; + return; } - } - if(address < 0xff80) - { gbMemory[address] = value; - return; - } - - gbMemory[address] = value; } uint8_t gbReadOpcode(register uint16_t address) { - if(gbCheatMap[address]) - return gbCheatRead(address); + if (gbCheatMap[address]) + return gbCheatRead(address); - if(address < 0x8000) - return gbMemoryMap[address>>12][address&0x0fff]; + if (address < 0x8000) + return gbMemoryMap[address >> 12][address & 0x0fff]; - if (address < 0xa000) - { - // A lot of 'ugly' checks... But only way to emulate this particular behaviour... - if ( - ( - (gbHardware & 0xa) && - ( - (gbLcdModeDelayed != 3) || - ( - ((register_LY == 0) && (gbScreenOn == false) && (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicksDelayed == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS)) - ) - ) - ) - || - ( - (gbHardware & 0x5) && - (gbLcdModeDelayed != 3) && - ( - (gbLcdMode != 3) || - ((register_LY == 0) && ((gbScreenOn == false) && (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicks == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS))) - ) - ) - ) - return gbMemoryMap[address >> 12][address & 0x0fff]; + if (address < 0xa000) { + // A lot of 'ugly' checks... But only way to emulate this particular behaviour... + if ( + ( + (gbHardware & 0xa) && ((gbLcdModeDelayed != 3) || (((register_LY == 0) && (gbScreenOn == false) && (register_LCDC & 0x80)) && (gbLcdLYIncrementTicksDelayed == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS))))) + || ((gbHardware & 0x5) && (gbLcdModeDelayed != 3) && ((gbLcdMode != 3) || ((register_LY == 0) && ((gbScreenOn == false) && (register_LCDC & 0x80)) && (gbLcdLYIncrementTicks == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS)))))) + return gbMemoryMap[address >> 12][address & 0x0fff]; - return 0xff; - } - - // Used for the mirroring of 0xC000 in 0xE000 - if ((address >= 0xe000) && (address < 0xfe00)) - address &= ~0x2000; - - switch(address & 0xf000) { - case 0x0a: - case 0x0b: - if(mapperReadRAM) - return mapperReadRAM(address); - break; - case 0x0f: - if(address > 0xff00) { - switch(address & 0x00ff) { - case 0x02: - return (gbMemory[0xff02]); - case 0x03: - return (0xff); - case 0x04: - return register_DIV; - case 0x05: - return register_TIMA; - case 0x06: - return register_TMA; - case 0x07: - return (0xf8 | register_TAC); - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - return (0xff); - case 0x0f: - return (0xe0 | gbMemory[0xff0f]); - case 0x40: - return register_LCDC; - case 0x41: - // This is a GB/C only bug (ie. not GBA/SP). - if ((gbHardware & 7) && (gbLcdMode == 2) && (gbLcdModeDelayed == 1) && (!gbSpeed)) - return (0x80 | (gbMemory[0xff41] & 0xFC)); - else - return (0x80 | gbMemory[0xff41]); - case 0x42: - return register_SCY; - case 0x43: - return register_SCX; - case 0x44: - if (((gbHardware & 7) && ((gbLcdMode == 1) && (gbLcdTicks == 0x71))) || - (!(register_LCDC & 0x80))) - return 0; - else - return register_LY; - case 0x45: - return register_LYC; - case 0x46: - return register_DMA; - case 0x4a: - return register_WY; - case 0x4b: - return register_WX; - case 0x4c: return 0xff; - 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 0x68: - case 0x6a: - if (gbCgbMode) - return (0x40 | gbMemory[address]); - else - return 0xc0; - case 0x69: - case 0x6b: - if (gbCgbMode) - { - // No access to gbPalette during mode 3 (Color Panel Demo) - if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || - (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || - ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || - ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) - return (gbMemory[address]); - else - return 0xff; - } - else - return 0xff; - case 0x70: - if (gbCgbMode) - return (0xf8 | register_SVBK); - else - return 0xff; - case 0xff: - return register_IE; - } } - // OAM not accessible during mode 2 & 3. - if(((address >= 0xfe00) && (address<0xfea0)) && - ((gbLcdMode | gbLcdModeDelayed) &2)) - return 0xff; - break; - } - if ((address >= 0xfea0) && (address < 0xff00)) - { - if (gbHardware & 1) - return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0x00 : 0xff ); - else if (gbHardware & 2) - return gbMemoryMap[address>>12][address & 0x0fff]; - else if (gbHardware & 4) - return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0xff : 0x00 ); - else if (gbHardware & 8) - return ((address & 0xf0) |((address & 0xf0)>>4)); - } + // Used for the mirroring of 0xC000 in 0xE000 + if ((address >= 0xe000) && (address < 0xfe00)) + address &= ~0x2000; - return gbMemoryMap[address>>12][address & 0x0fff]; + switch (address & 0xf000) { + case 0x0a: + case 0x0b: + if (mapperReadRAM) + return mapperReadRAM(address); + break; + case 0x0f: + if (address > 0xff00) { + switch (address & 0x00ff) { + case 0x02: + return (gbMemory[0xff02]); + case 0x03: + return (0xff); + case 0x04: + return register_DIV; + case 0x05: + return register_TIMA; + case 0x06: + return register_TMA; + case 0x07: + return (0xf8 | register_TAC); + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + return (0xff); + case 0x0f: + return (0xe0 | gbMemory[0xff0f]); + case 0x40: + return register_LCDC; + case 0x41: + // This is a GB/C only bug (ie. not GBA/SP). + if ((gbHardware & 7) && (gbLcdMode == 2) && (gbLcdModeDelayed == 1) && (!gbSpeed)) + return (0x80 | (gbMemory[0xff41] & 0xFC)); + else + return (0x80 | gbMemory[0xff41]); + case 0x42: + return register_SCY; + case 0x43: + return register_SCX; + case 0x44: + if (((gbHardware & 7) && ((gbLcdMode == 1) && (gbLcdTicks == 0x71))) || (!(register_LCDC & 0x80))) + return 0; + else + return register_LY; + case 0x45: + return register_LYC; + case 0x46: + return register_DMA; + case 0x4a: + return register_WY; + case 0x4b: + return register_WX; + case 0x4c: + return 0xff; + 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 0x68: + case 0x6a: + if (gbCgbMode) + return (0x40 | gbMemory[address]); + else + return 0xc0; + case 0x69: + case 0x6b: + if (gbCgbMode) { + // No access to gbPalette during mode 3 (Color Panel Demo) + if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks >= (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299] - 1)))) && (!gbSpeed)) || (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || ((gbLcdMode == 3) && (gbLcdTicks > (GBLCD_MODE_3_CLOCK_TICKS - 2))) || ((gbLcdMode == 0) && (gbLcdTicks <= (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299] - 2)))))) + return (gbMemory[address]); + else + return 0xff; + } else + return 0xff; + case 0x70: + if (gbCgbMode) + return (0xf8 | register_SVBK); + else + return 0xff; + case 0xff: + return register_IE; + } + } + // OAM not accessible during mode 2 & 3. + if (((address >= 0xfe00) && (address < 0xfea0)) && ((gbLcdMode | gbLcdModeDelayed) & 2)) + return 0xff; + break; + } + + if ((address >= 0xfea0) && (address < 0xff00)) { + if (gbHardware & 1) + return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0x00 : 0xff); + else if (gbHardware & 2) + return gbMemoryMap[address >> 12][address & 0x0fff]; + else if (gbHardware & 4) + return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0xff : 0x00); + else if (gbHardware & 8) + return ((address & 0xf0) | ((address & 0xf0) >> 4)); + } + + return gbMemoryMap[address >> 12][address & 0x0fff]; } uint8_t gbReadMemory(register uint16_t address) { - if(gbCheatMap[address]) - return gbCheatRead(address); + if (gbCheatMap[address]) + return gbCheatRead(address); + if (address < 0x8000) + return gbMemoryMap[address >> 12][address & 0x0fff]; - if(address < 0x8000) - return gbMemoryMap[address>>12][address&0x0fff]; + if (address < 0xa000) { + // A lot of 'ugly' checks... But only way to emulate this particular behaviour... + if ( + ( + (gbHardware & 0xa) && ((gbLcdModeDelayed != 3) || (((register_LY == 0) && (gbScreenOn == false) && (register_LCDC & 0x80)) && (gbLcdLYIncrementTicksDelayed == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS))))) + || ((gbHardware & 0x5) && (gbLcdModeDelayed != 3) && ((gbLcdMode != 3) || ((register_LY == 0) && ((gbScreenOn == false) && (register_LCDC & 0x80)) && (gbLcdLYIncrementTicks == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS)))))) + return gbMemoryMap[address >> 12][address & 0x0fff]; - - if (address < 0xa000) - { - // A lot of 'ugly' checks... But only way to emulate this particular behaviour... - if ( - ( - (gbHardware & 0xa) && - ( - (gbLcdModeDelayed != 3) || - ( - ((register_LY == 0) && (gbScreenOn == false) && (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicksDelayed == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS)) - ) - ) - ) - || - ( - (gbHardware & 0x5) && - (gbLcdModeDelayed != 3) && - ( - (gbLcdMode != 3) || - ((register_LY == 0) && ((gbScreenOn == false) && (register_LCDC & 0x80)) && - (gbLcdLYIncrementTicks == (GBLY_INCREMENT_CLOCK_TICKS - GBLCD_MODE_2_CLOCK_TICKS))) - ) - ) - ) - return gbMemoryMap[address >> 12][address & 0x0fff]; - - return 0xff; - } - - if ((address >= 0xe000) && (address < 0xfe00)) - address &= ~0x2000; - - if(address < 0xc000) { -#ifndef FINAL_VERSION - if(memorydebug) { - log("Memory register read %04x PC=%04x\n", - address, - PC.W); + return 0xff; } + + if ((address >= 0xe000) && (address < 0xfe00)) + address &= ~0x2000; + + if (address < 0xc000) { +#ifndef FINAL_VERSION + if (memorydebug) { + log("Memory register read %04x PC=%04x\n", + address, + PC.W); + } #endif - // for the 2kb ram limit (fixes crash in shawu's story - // but now its sram test fails, as the it expects 8kb and not 2kb... - // So use the 'genericflashcard' option to fix it). - if (address<=(0xa000+gbRamSizeMask)) - { - if(mapperReadRAM) - return mapperReadRAM(address); - return gbMemoryMap[address>>12][address & 0x0fff]; - } - return 0xff; - } - - if(address >= 0xff00) { - if ( address >= 0xFF10 && address <= 0xFF3F ) - return gbSoundRead( address ); - - switch(address & 0x00ff) { - case 0x00: - { - if(gbSgbMode) { - gbSgbReadingController |= 4; - gbSgbResetPacketState(); + // for the 2kb ram limit (fixes crash in shawu's story + // but now its sram test fails, as the it expects 8kb and not 2kb... + // So use the 'genericflashcard' option to fix it). + if (address <= (0xa000 + gbRamSizeMask)) { + if (mapperReadRAM) + return mapperReadRAM(address); + return gbMemoryMap[address >> 12][address & 0x0fff]; } - - 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; - } - } - } - return gbMemory[0xff00]; - break; - case 0x01: - return gbMemory[0xff01]; - case 0x02: - return (gbMemory[0xff02]); - 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 | gbMemory[0xff0f]); - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - if ((gbMemory[NR30] & 0x80) && (gbMemory[NR34] & 0x80)) - return 0xFF; - else - return gbMemoryMap[address>>12][address & 0x0fff]; - case 0x40: - return register_LCDC; - case 0x41: - // This is a GB/C only bug (ie. not GBA/SP). - if ((gbHardware & 7) && (gbLcdMode == 2) && (gbLcdModeDelayed == 1) && (!gbSpeed)) - return (0x80 | (gbMemory[0xff41] & 0xFC)); - else - return (0x80 | gbMemory[0xff41]); - case 0x42: - return register_SCY; - case 0x43: - return register_SCX; - case 0x44: - if (((gbHardware & 7) && ((gbLcdMode == 1) && (gbLcdTicks == 0x71))) || - (!(register_LCDC & 0x80))) - return (0); - else - 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 0x68: - case 0x6a: - if (gbCgbMode) - return (0x40 | gbMemory[address]); - else - return 0xc0; - case 0x69: - case 0x6b: - if (gbCgbMode) - { - // No access to gbPalette during mode 3 (Color Panel Demo) - if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || - (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || - ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || - ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) - return (gbMemory[address]); - else - return 0xff; - } - else return 0xff; - case 0x70: - if (gbCgbMode) - return (0xf8 | register_SVBK); - else - return 0xff; - case 0xff: - return register_IE; } - } - // OAM not accessible during mode 2 & 3. - if(((address >= 0xfe00) && (address<0xfea0)) && - ((((gbLcdMode | gbLcdModeDelayed) & 2) && - (!(gbSpeed && (gbHardware & 0x2) && !(gbLcdModeDelayed & 2) && (gbLcdMode == 2)))) || - (gbSpeed && (gbHardware & 0x2) && (gbLcdModeDelayed == 0) && (gbLcdTicksDelayed == (GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]))))) - return 0xff; - if ((address >= 0xfea0) && (address < 0xff00)) - { - if (gbHardware & 1) - return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0x00 : 0xff ); - else if (gbHardware & 2) - return gbMemoryMap[address>>12][address & 0x0fff]; - else if (gbHardware & 4) - return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0xff : 0x00 ); - else if (gbHardware & 8) - return ((address & 0xf0) |((address & 0xf0)>>4)); - } + if (address >= 0xff00) { + if (address >= 0xFF10 && address <= 0xFF3F) + return gbSoundRead(address); - return gbMemoryMap[address>>12][address & 0x0fff]; + 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; + } + } + } + return gbMemory[0xff00]; + break; + case 0x01: + return gbMemory[0xff01]; + case 0x02: + return (gbMemory[0xff02]); + 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 | gbMemory[0xff0f]); + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + if ((gbMemory[NR30] & 0x80) && (gbMemory[NR34] & 0x80)) + return 0xFF; + else + return gbMemoryMap[address >> 12][address & 0x0fff]; + case 0x40: + return register_LCDC; + case 0x41: + // This is a GB/C only bug (ie. not GBA/SP). + if ((gbHardware & 7) && (gbLcdMode == 2) && (gbLcdModeDelayed == 1) && (!gbSpeed)) + return (0x80 | (gbMemory[0xff41] & 0xFC)); + else + return (0x80 | gbMemory[0xff41]); + case 0x42: + return register_SCY; + case 0x43: + return register_SCX; + case 0x44: + if (((gbHardware & 7) && ((gbLcdMode == 1) && (gbLcdTicks == 0x71))) || (!(register_LCDC & 0x80))) + return (0); + else + 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 0x68: + case 0x6a: + if (gbCgbMode) + return (0x40 | gbMemory[address]); + else + return 0xc0; + case 0x69: + case 0x6b: + if (gbCgbMode) { + // No access to gbPalette during mode 3 (Color Panel Demo) + if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks >= (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299] - 1)))) && (!gbSpeed)) || (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || ((gbLcdMode == 3) && (gbLcdTicks > (GBLCD_MODE_3_CLOCK_TICKS - 2))) || ((gbLcdMode == 0) && (gbLcdTicks <= (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299] - 2)))))) + return (gbMemory[address]); + else + return 0xff; + } else + return 0xff; + case 0x70: + if (gbCgbMode) + return (0xf8 | register_SVBK); + else + return 0xff; + case 0xff: + return register_IE; + } + } + // OAM not accessible during mode 2 & 3. + if (((address >= 0xfe00) && (address < 0xfea0)) && ((((gbLcdMode | gbLcdModeDelayed) & 2) && (!(gbSpeed && (gbHardware & 0x2) && !(gbLcdModeDelayed & 2) && (gbLcdMode == 2)))) || (gbSpeed && (gbHardware & 0x2) && (gbLcdModeDelayed == 0) && (gbLcdTicksDelayed == (GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299]))))) + return 0xff; + + if ((address >= 0xfea0) && (address < 0xff00)) { + if (gbHardware & 1) + return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0x00 : 0xff); + else if (gbHardware & 2) + return gbMemoryMap[address >> 12][address & 0x0fff]; + else if (gbHardware & 4) + return ((((address + ((address >> 4) - 0xfea)) >> 2) & 1) ? 0xff : 0x00); + else if (gbHardware & 8) + return ((address & 0xf0) | ((address & 0xf0) >> 4)); + } + + return gbMemoryMap[address >> 12][address & 0x0fff]; } void gbVblank_interrupt() { - gbCheatWrite(false); // Emulates GS codes. - gbMemory[0xff0f] = register_IF &= 0xfe; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x40; + gbCheatWrite(false); // Emulates GS codes. + gbMemory[0xff0f] = register_IF &= 0xfe; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x40; } void gbLcd_interrupt() { - gbCheatWrite(false); // Emulates GS codes. - gbMemory[0xff0f] = register_IF &= 0xfd; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x48; + gbCheatWrite(false); // Emulates GS codes. + gbMemory[0xff0f] = register_IF &= 0xfd; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x48; } void gbTimer_interrupt() { - gbMemory[0xff0f] = register_IF &= 0xfb; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x50; + gbMemory[0xff0f] = register_IF &= 0xfb; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x50; } void gbSerial_interrupt() { - gbMemory[0xff0f] = register_IF &= 0xf7; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x58; + gbMemory[0xff0f] = register_IF &= 0xf7; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x58; } void gbJoypad_interrupt() { - gbMemory[0xff0f] = register_IF &= 0xef; - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x60; + gbMemory[0xff0f] = register_IF &= 0xef; + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x60; } void gbSpeedSwitch() { - gbBlackScreen = true; - if(gbSpeed == 0) { - gbSpeed = 1; - GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; - GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; - GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; - GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; - GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; - GBDIV_CLOCK_TICKS = 64; - 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 * 2; - gbLcdTicks *= 2; - gbLcdTicksDelayed *=2; - gbLcdTicksDelayed--; - gbLcdLYIncrementTicks *= 2; - gbLcdLYIncrementTicksDelayed *= 2; - gbLcdLYIncrementTicksDelayed--; - gbSerialTicks *= 2; - //SOUND_CLOCK_TICKS = soundQuality * 24 * 2; - //soundTicks *= 2; - gbLine99Ticks = 3; - } 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; - GBLY_INCREMENT_CLOCK_TICKS = 114; - GBDIV_CLOCK_TICKS = 64; - 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; - gbLcdTicks >>= 1; - gbLcdTicksDelayed++; - gbLcdTicksDelayed >>=1; - gbLcdLYIncrementTicks >>= 1; - gbLcdLYIncrementTicksDelayed++; - gbLcdLYIncrementTicksDelayed >>= 1; - gbSerialTicks /= 2; - //SOUND_CLOCK_TICKS = soundQuality * 24; - //soundTicks /= 2; - gbLine99Ticks = 1; - if (gbHardware & 8) - gbLine99Ticks++; - } - gbDmaTicks += (134)*GBLY_INCREMENT_CLOCK_TICKS + (37<<(gbSpeed ? 1 : 0)); -} - -bool CPUIsGBBios(const char * file) -{ - if(strlen(file) > 4) { - const char * p = strrchr(file,'.'); - - if(p != NULL) { - if(_stricmp(p, ".gb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".bios") == 0) - return true; - if(_stricmp(p, ".rom") == 0) - return true; + gbBlackScreen = true; + if (gbSpeed == 0) { + gbSpeed = 1; + GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; + GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; + GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; + GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; + GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; + GBDIV_CLOCK_TICKS = 64; + 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 * 2; + gbLcdTicks *= 2; + gbLcdTicksDelayed *= 2; + gbLcdTicksDelayed--; + gbLcdLYIncrementTicks *= 2; + gbLcdLYIncrementTicksDelayed *= 2; + gbLcdLYIncrementTicksDelayed--; + gbSerialTicks *= 2; + //SOUND_CLOCK_TICKS = soundQuality * 24 * 2; + //soundTicks *= 2; + gbLine99Ticks = 3; + } 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; + GBLY_INCREMENT_CLOCK_TICKS = 114; + GBDIV_CLOCK_TICKS = 64; + 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; + gbLcdTicks >>= 1; + gbLcdTicksDelayed++; + gbLcdTicksDelayed >>= 1; + gbLcdLYIncrementTicks >>= 1; + gbLcdLYIncrementTicksDelayed++; + gbLcdLYIncrementTicksDelayed >>= 1; + gbSerialTicks /= 2; + //SOUND_CLOCK_TICKS = soundQuality * 24; + //soundTicks /= 2; + gbLine99Ticks = 1; + if (gbHardware & 8) + gbLine99Ticks++; } - } - - return false; + gbDmaTicks += (134) * GBLY_INCREMENT_CLOCK_TICKS + (37 << (gbSpeed ? 1 : 0)); } -void gbCPUInit(const char *biosFileName, bool useBiosFile) +bool CPUIsGBBios(const char* file) { - // GB/GBC/SGB only at the moment - if (!(gbHardware & 7)) - return; + if (strlen(file) > 4) { + const char* p = strrchr(file, '.'); - useBios = false; - if (useBiosFile) - { - int expectedSize = (gbHardware & 2) ? 0x900 : 0x100; - int size = expectedSize; - if(utilLoad(biosFileName, + if (p != NULL) { + if (_stricmp(p, ".gb") == 0) + return true; + if (_stricmp(p, ".bin") == 0) + return true; + if (_stricmp(p, ".bios") == 0) + return true; + if (_stricmp(p, ".rom") == 0) + return true; + } + } + + return false; +} + +void gbCPUInit(const char* biosFileName, bool useBiosFile) +{ + // GB/GBC/SGB only at the moment + if (!(gbHardware & 7)) + return; + + useBios = false; + if (useBiosFile) { + int expectedSize = (gbHardware & 2) ? 0x900 : 0x100; + int size = expectedSize; + if (utilLoad(biosFileName, CPUIsGBBios, bios, size)) { - if(size == expectedSize) - useBios = true; - else - systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file size")); + if (size == expectedSize) + useBios = true; + else + systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file size")); + } } - } } void gbGetHardwareType() { - gbCgbMode = 0; - gbSgbMode = 0; - if((gbEmulatorType == 0 && (gbRom[0x143] & 0x80)) || - gbEmulatorType == 1 || - gbEmulatorType == 4) { - gbCgbMode = 1; - } + gbCgbMode = 0; + gbSgbMode = 0; + if ((gbEmulatorType == 0 && (gbRom[0x143] & 0x80)) || gbEmulatorType == 1 || gbEmulatorType == 4) { + gbCgbMode = 1; + } - if((gbCgbMode == 0 ) && (gbRom[0x146] == 0x03)) { - if(gbEmulatorType == 0 || - gbEmulatorType == 2 || - gbEmulatorType == 5) - gbSgbMode = 1; - } + if ((gbCgbMode == 0) && (gbRom[0x146] == 0x03)) { + if (gbEmulatorType == 0 || gbEmulatorType == 2 || gbEmulatorType == 5) + gbSgbMode = 1; + } - gbHardware = 1; // GB - if (((gbCgbMode == 1) && (gbEmulatorType == 0)) || (gbEmulatorType == 1)) - gbHardware = 2; // GBC - else if (((gbSgbMode == 1) && (gbEmulatorType == 0)) || (gbEmulatorType == 2) || (gbEmulatorType == 5)) - gbHardware = 4; // SGB(2) - else if (gbEmulatorType == 4) - gbHardware = 8; // GBA + gbHardware = 1; // GB + if (((gbCgbMode == 1) && (gbEmulatorType == 0)) || (gbEmulatorType == 1)) + gbHardware = 2; // GBC + else if (((gbSgbMode == 1) && (gbEmulatorType == 0)) || (gbEmulatorType == 2) || (gbEmulatorType == 5)) + gbHardware = 4; // SGB(2) + else if (gbEmulatorType == 4) + gbHardware = 8; // GBA - gbGBCColorType = 0; - if (gbHardware & 8) // If GBA is selected, choose the GBA default settings. - gbGBCColorType = 2; // (0 = GBC, 1 = GBA, 2 = GBASP) + gbGBCColorType = 0; + if (gbHardware & 8) // If GBA is selected, choose the GBA default settings. + gbGBCColorType = 2; // (0 = GBC, 1 = GBA, 2 = GBASP) } static void gbSelectColorizationPalette() { - int infoIdx = 0; + int infoIdx = 0; - // Check if licensee is Nintendo. If not, use default palette. - if (gbRom[0x014B] == 0x01 || - (gbRom[0x014B] == 0x33 && gbRom[0x0144] == 0x30 && gbRom[0x0145] == 0x31)) - { - // Calculate the checksum over 16 title bytes. - uint8_t checksum = 0; - for (int i = 0; i < 16; i++) - { - checksum += gbRom[0x0134 + i]; - } - - // Check if the checksum is in the list. - int idx; - for (idx = 0; idx < sizeof(gbColorizationChecksums); idx++) - { - if (gbColorizationChecksums[idx] == checksum) - { - break; - } - } - - // Was the checksum found in the list? - if (idx < sizeof(gbColorizationChecksums)) - { - // Indexes above 0x40 have to be disambiguated. - if (idx > 0x40) - { - // No idea how that works. But it works. - for (int i = idx - 0x41, j = 0; i < sizeof(gbColorizationDisambigChars); i += 14, j += 14) - { - if (gbRom[0x0137] == gbColorizationDisambigChars[i]) - { - infoIdx = idx + j; - break; - } + // Check if licensee is Nintendo. If not, use default palette. + if (gbRom[0x014B] == 0x01 || (gbRom[0x014B] == 0x33 && gbRom[0x0144] == 0x30 && gbRom[0x0145] == 0x31)) { + // Calculate the checksum over 16 title bytes. + uint8_t checksum = 0; + for (int i = 0; i < 16; i++) { + checksum += gbRom[0x0134 + i]; + } + + // Check if the checksum is in the list. + int idx; + for (idx = 0; idx < sizeof(gbColorizationChecksums); idx++) { + if (gbColorizationChecksums[idx] == checksum) { + break; + } + } + + // Was the checksum found in the list? + if (idx < sizeof(gbColorizationChecksums)) { + // Indexes above 0x40 have to be disambiguated. + if (idx > 0x40) { + // No idea how that works. But it works. + for (int i = idx - 0x41, j = 0; i < sizeof(gbColorizationDisambigChars); i += 14, j += 14) { + if (gbRom[0x0137] == gbColorizationDisambigChars[i]) { + infoIdx = idx + j; + break; + } + } + } else { + // Lower indexes just use the index from the checksum list. + infoIdx = idx; + } } - } - else - { - // Lower indexes just use the index from the checksum list. - infoIdx = idx; - } } - } - uint8_t palette = gbColorizationPaletteInfo[infoIdx] & 0x1F; - uint8_t flags = (gbColorizationPaletteInfo[infoIdx] & 0xE0) >> 5; + uint8_t palette = gbColorizationPaletteInfo[infoIdx] & 0x1F; + uint8_t flags = (gbColorizationPaletteInfo[infoIdx] & 0xE0) >> 5; + // Normally the first palette is used as OBP0. + // If bit 0 is zero, the third palette is used instead. + const uint16_t* obp0 = 0; + if (flags & 1) { + obp0 = gbColorizationPaletteData[palette][0]; + } else { + obp0 = gbColorizationPaletteData[palette][2]; + } - // Normally the first palette is used as OBP0. - // If bit 0 is zero, the third palette is used instead. - const uint16_t* obp0 = 0; - if (flags & 1) - { - obp0 = gbColorizationPaletteData[palette][0]; - } - else - { - obp0 = gbColorizationPaletteData[palette][2]; - } + memcpy(gbPalette + 32, obp0, sizeof(gbColorizationPaletteData[palette][0])); - memcpy(gbPalette + 32, obp0, sizeof(gbColorizationPaletteData[palette][0])); + // Normally the second palette is used as OBP1. + // If bit 1 is set, the first palette is used instead. + // If bit 2 is zero, the third palette is used instead. + const uint16_t* obp1 = 0; + if (!(flags & 4)) { + obp1 = gbColorizationPaletteData[palette][2]; + } else if (flags & 2) { + obp1 = gbColorizationPaletteData[palette][0]; + } else { + obp1 = gbColorizationPaletteData[palette][1]; + } - // Normally the second palette is used as OBP1. - // If bit 1 is set, the first palette is used instead. - // If bit 2 is zero, the third palette is used instead. - const uint16_t* obp1 = 0; - if (!(flags & 4)) - { - obp1 = gbColorizationPaletteData[palette][2]; - } - else if (flags & 2) - { - obp1 = gbColorizationPaletteData[palette][0]; - } - else - { - obp1 = gbColorizationPaletteData[palette][1]; - } + memcpy(gbPalette + 36, obp1, sizeof(gbColorizationPaletteData[palette][0])); - memcpy(gbPalette + 36, obp1, sizeof(gbColorizationPaletteData[palette][0])); - - // Third palette is always used for BGP. - memcpy(gbPalette, gbColorizationPaletteData[palette][2], sizeof(gbColorizationPaletteData[palette][0])); + // Third palette is always used for BGP. + memcpy(gbPalette, gbColorizationPaletteData[palette][2], sizeof(gbColorizationPaletteData[palette][0])); } void gbReset() { #ifndef NO_LINK - if (GetLinkMode() == LINK_GAMEBOY_IPC || GetLinkMode() == LINK_GAMEBOY_SOCKET) { - EmuReseted = true; - gbInitLink(); - } + if (GetLinkMode() == LINK_GAMEBOY_IPC || GetLinkMode() == LINK_GAMEBOY_SOCKET) { + EmuReseted = true; + gbInitLink(); + } #endif - gbGetHardwareType(); + gbGetHardwareType(); - oldRegister_WY = 146; - gbInterruptLaunched = 0; + oldRegister_WY = 146; + gbInterruptLaunched = 0; - if(gbCgbMode == 1) { - if (gbVram == NULL) - gbVram = (uint8_t *)malloc(0x4000); - if (gbWram == NULL) - gbWram = (uint8_t *)malloc(0x8000); - memset(gbVram,0,0x4000); - memset(gbPalette,0, 2*128); - } - else - { - if(gbVram != NULL) { - free(gbVram); - gbVram = NULL; - } - if(gbWram != NULL) { - free(gbWram); - gbWram = NULL; - } - } - - gbLYChangeHappened = false; - gbLCDChangeHappened = false; - gbBlackScreen = false; - gbInterruptWait = 0; - gbDmaTicks = 0; - clockTicks = 0; - - // clean Wram - // This kinda emulates the startup state of Wram on GB/C (not very accurate, - // but way closer to the reality than filling it with 00es or FFes). - // On GBA/GBASP, it's kinda filled with random data. - // In all cases, most of the 2nd bank is filled with 00s. - // The starting data are important for some 'buggy' games, like Buster Brothers or - // Karamuchou ha Oosawagi!. - if (gbMemory != NULL) - { - memset(gbMemory,0xff, 65536); - for (int temp = 0xC000; temp < 0xE000; temp++) - if ((temp & 0x8) ^((temp & 0x800)>>8)) - { - if ((gbHardware & 0x02) && (gbGBCColorType == 0)) - gbMemory[temp] = 0x0; - else - gbMemory[temp] = 0x0f; - } - - else - gbMemory[temp] = 0xff; - } - - if(gbSpeed) { - gbSpeedSwitch(); - gbMemory[0xff4d] = 0; - } - - // GB bios set this memory area to 0 - // Fixes Pitman (J) title screen - if (gbHardware & 0x1) { - memset(&gbMemory[0x8000], 0x0, 0x2000); - } - - // clean LineBuffer - if (gbLineBuffer != NULL) - memset(gbLineBuffer, 0, sizeof(*gbLineBuffer)); - // clean Pix - if (pix != NULL) - memset(pix, 0, sizeof(*pix)); - // clean Vram - if (gbVram != NULL) - memset(gbVram, 0, 0x4000); - // clean Wram 2 - // This kinda emulates the startup state of Wram on GBC (not very accurate, - // but way closer to the reality than filling it with 00es or FFes). - // On GBA/GBASP, it's kinda filled with random data. - // In all cases, most of the 2nd bank is filled with 00s. - // The starting data are important for some 'buggy' games, like Buster Brothers or - // Karamuchou ha Oosawagi! - if (gbWram != NULL) - { - for (int i = 0; i<8; i++) - if (i != 2) - memcpy ((uint16_t *)(gbWram+i*0x1000), (uint16_t *)(gbMemory+0xC000), 0x1000); - } - - memset(gbSCYLine,0,sizeof(gbSCYLine)); - memset(gbSCXLine,0,sizeof(gbSCXLine)); - memset(gbBgpLine,0xfc,sizeof(gbBgpLine)); - if (gbHardware & 5) - { - memset(gbObp0Line,0xff,sizeof(gbObp0Line)); - memset(gbObp1Line,0xff,sizeof(gbObp1Line)); - } - else - { - memset(gbObp0Line,0x0,sizeof(gbObp0Line)); - memset(gbObp1Line,0x0,sizeof(gbObp1Line)); - } - memset(gbSpritesTicks,0x0,sizeof(gbSpritesTicks)); - - SP.W = 0xfffe; - AF.W = 0x01b0; - BC.W = 0x0013; - DE.W = 0x00d8; - HL.W = 0x014d; - PC.W = 0x0100; - IFF = 0; - gbInt48Signal = 0; - - register_TIMA = 0; - register_TMA = 0; - register_TAC = 0; - gbMemory[0xff0f] = register_IF = 1; - gbMemory[0xff40] = register_LCDC = 0x91; - gbMemory[0xff47] = 0xfc; - - if (gbCgbMode) - gbMemory[0xff4d] = 0x7e; - else - gbMemory[0xff4d] = 0xff; - - if (!gbCgbMode) - gbMemory[0xff70] = gbMemory[0xff74] = 0xff; - - if (gbCgbMode) - gbMemory[0xff56] = 0x3e; - else - gbMemory[0xff56] = 0xff; - - register_SCY = 0; - register_SCX = 0; - register_LYC = 0; - register_DMA = 0xff; - register_WY = 0; - register_WX = 0; - register_VBK = 0; - register_HDMA1 = 0xff; - register_HDMA2 = 0xff; - register_HDMA3 = 0xff; - register_HDMA4 = 0xff; - register_HDMA5 = 0xff; - register_SVBK = 0; - register_IE = 0; - - if (gbCgbMode) - gbMemory[0xff02] = 0x7c; - else - gbMemory[0xff02] = 0x7e; - - gbMemory[0xff03] = 0xff; - int i; - for (i = 0x8; i<0xf; i++) - gbMemory[0xff00+i] = 0xff; - - gbMemory[0xff13] = 0xff; - gbMemory[0xff15] = 0xff; - gbMemory[0xff18] = 0xff; - gbMemory[0xff1d] = 0xff; - gbMemory[0xff1f] = 0xff; - - for (i = 0x27; i<0x30; i++) - gbMemory[0xff00+i] = 0xff; - - gbMemory[0xff4c] = 0xff; - gbMemory[0xff4e] = 0xff; - gbMemory[0xff50] = 0xff; - - for (i = 0x57; i<0x68; i++) - gbMemory[0xff00+i] = 0xff; - - for (i = 0x5d; i<0x70; i++) - gbMemory[0xff00+i] = 0xff; - - gbMemory[0xff71] = 0xff; - - for (i = 0x78; i<0x80; i++) - gbMemory[0xff00+i] = 0xff; - - if (gbHardware & 0xa) - { - - if (gbHardware & 2) - { - AF.W = 0x1180; - BC.W = 0x0000; - } - else - { - AF.W = 0x1100; - BC.W = 0x0100; // GBA/SP have B = 0x01 (which means GBC & GBA/SP bootrom are different !) - } - - gbMemory[0xff26] = 0xf1; - if (gbCgbMode) - { - - gbMemory[0xff31] = 0xff; - gbMemory[0xff33] = 0xff; - gbMemory[0xff35] = 0xff; - gbMemory[0xff37] = 0xff; - gbMemory[0xff39] = 0xff; - gbMemory[0xff3b] = 0xff; - gbMemory[0xff3d] = 0xff; - - gbMemory[0xff44] = register_LY = 0x90; - gbDivTicks = 0x19 + ((gbHardware & 2) >> 1); - gbInternalTimer = 0x58 + ((gbHardware & 2) >> 1); - gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS - - (register_LY-0x8F)*GBLY_INCREMENT_CLOCK_TICKS + 72 + ((gbHardware & 2) >> 1); - gbLcdLYIncrementTicks = 72 + ((gbHardware & 2) >> 1); - gbMemory[0xff04] = register_DIV = 0x1E; - } - else - { - gbMemory[0xff44] = register_LY = 0x94; - gbDivTicks = 0x22 + ((gbHardware & 2) >> 1); - gbInternalTimer = 0x61 + ((gbHardware & 2) >> 1); - gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS - - (register_LY-0x8F)*GBLY_INCREMENT_CLOCK_TICKS + 25 + ((gbHardware & 2) >> 1); - gbLcdLYIncrementTicks = 25 + ((gbHardware & 2) >> 1); - gbMemory[0xff04] = register_DIV = 0x26; + if (gbCgbMode == 1) { + if (gbVram == NULL) + gbVram = (uint8_t*)malloc(0x4000); + if (gbWram == NULL) + gbWram = (uint8_t*)malloc(0x8000); + memset(gbVram, 0, 0x4000); + memset(gbPalette, 0, 2 * 128); + } else { + if (gbVram != NULL) { + free(gbVram); + gbVram = NULL; + } + if (gbWram != NULL) { + free(gbWram); + gbWram = NULL; + } } + gbLYChangeHappened = false; + gbLCDChangeHappened = false; + gbBlackScreen = false; + gbInterruptWait = 0; + gbDmaTicks = 0; + clockTicks = 0; - DE.W = 0xff56; - HL.W = 0x000d; + // clean Wram + // This kinda emulates the startup state of Wram on GB/C (not very accurate, + // but way closer to the reality than filling it with 00es or FFes). + // On GBA/GBASP, it's kinda filled with random data. + // In all cases, most of the 2nd bank is filled with 00s. + // The starting data are important for some 'buggy' games, like Buster Brothers or + // Karamuchou ha Oosawagi!. + if (gbMemory != NULL) { + memset(gbMemory, 0xff, 65536); + for (int temp = 0xC000; temp < 0xE000; temp++) + if ((temp & 0x8) ^ ((temp & 0x800) >> 8)) { + if ((gbHardware & 0x02) && (gbGBCColorType == 0)) + gbMemory[temp] = 0x0; + else + gbMemory[temp] = 0x0f; + } - register_HDMA5 = 0xff; - gbMemory[0xff68] = 0xc0; - gbMemory[0xff6a] = 0xc0; - - - gbMemory[0xff41] = register_STAT = 0x81; - gbLcdMode = 1; - } - else - { - if (gbHardware & 4) - { - if(gbEmulatorType == 5) - AF.W = 0xffb0; - else - AF.W = 0x01b0; - BC.W = 0x0013; - DE.W = 0x00d8; - HL.W = 0x014d; + else + gbMemory[temp] = 0xff; } - gbDivTicks = 14; - gbInternalTimer = gbDivTicks--; - gbMemory[0xff04] = register_DIV = 0xAB; - gbMemory[0xff41] = register_STAT = 0x85; - gbMemory[0xff44] = register_LY = 0x00; - gbLcdTicks = 15; - gbLcdLYIncrementTicks = 114+gbLcdTicks; - gbLcdMode = 1; - } - - // used for the handling of the gb Boot Rom - if ((gbHardware & 7) && (bios != NULL) && useBios && !skipBios) - { - if (gbHardware & 5) - { - memcpy ((uint8_t *)(gbMemory), (uint8_t *)(gbRom), 0x1000); - memcpy ((uint8_t *)(gbMemory), (uint8_t *)(bios), 0x100); + if (gbSpeed) { + gbSpeedSwitch(); + gbMemory[0xff4d] = 0; } - else - { - memcpy ((uint8_t *)(gbMemory), (uint8_t *)(bios), 0x900); - memcpy ((uint8_t *)(gbMemory + 0x100), (uint8_t *)(gbRom + 0x100), 0x100); - } - gbWhiteScreen = 0; - gbInternalTimer = 0x3e; - gbDivTicks = 0x3f; - gbMemory[0xff04] = register_DIV = 0x00; - PC.W = 0x0000; - register_LCDC = 0x11; - gbScreenOn = false; - gbLcdTicks = 0; - gbLcdMode = 0; - gbLcdModeDelayed = 0; - gbMemory[0xff41] = register_STAT &= 0xfc; + // GB bios set this memory area to 0 + // Fixes Pitman (J) title screen + if (gbHardware & 0x1) { + memset(&gbMemory[0x8000], 0x0, 0x2000); + } + + // clean LineBuffer + if (gbLineBuffer != NULL) + memset(gbLineBuffer, 0, sizeof(*gbLineBuffer)); + // clean Pix + if (pix != NULL) + memset(pix, 0, sizeof(*pix)); + // clean Vram + if (gbVram != NULL) + memset(gbVram, 0, 0x4000); + // clean Wram 2 + // This kinda emulates the startup state of Wram on GBC (not very accurate, + // but way closer to the reality than filling it with 00es or FFes). + // On GBA/GBASP, it's kinda filled with random data. + // In all cases, most of the 2nd bank is filled with 00s. + // The starting data are important for some 'buggy' games, like Buster Brothers or + // Karamuchou ha Oosawagi! + if (gbWram != NULL) { + for (int i = 0; i < 8; i++) + if (i != 2) + memcpy((uint16_t*)(gbWram + i * 0x1000), (uint16_t*)(gbMemory + 0xC000), 0x1000); + } + + memset(gbSCYLine, 0, sizeof(gbSCYLine)); + memset(gbSCXLine, 0, sizeof(gbSCXLine)); + memset(gbBgpLine, 0xfc, sizeof(gbBgpLine)); + if (gbHardware & 5) { + memset(gbObp0Line, 0xff, sizeof(gbObp0Line)); + memset(gbObp1Line, 0xff, sizeof(gbObp1Line)); + } else { + memset(gbObp0Line, 0x0, sizeof(gbObp0Line)); + memset(gbObp1Line, 0x0, sizeof(gbObp1Line)); + } + memset(gbSpritesTicks, 0x0, sizeof(gbSpritesTicks)); + + SP.W = 0xfffe; + AF.W = 0x01b0; + BC.W = 0x0013; + DE.W = 0x00d8; + HL.W = 0x014d; + PC.W = 0x0100; + IFF = 0; gbInt48Signal = 0; - gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS; - gbMemory[0xff6c] = 0xfe; - inBios = true; - } - else if (gbHardware & 0xa) - { - // Set compatibility mode if it is a DMG ROM. - gbMemory[0xff6c] = 0xfe | (uint8_t)!(gbRom[0x143] & 0x80); - } + register_TIMA = 0; + register_TMA = 0; + register_TAC = 0; + gbMemory[0xff0f] = register_IF = 1; + gbMemory[0xff40] = register_LCDC = 0x91; + gbMemory[0xff47] = 0xfc; + if (gbCgbMode) + gbMemory[0xff4d] = 0x7e; + else + gbMemory[0xff4d] = 0xff; - gbLine99Ticks = 1; - if (gbHardware & 8) - gbLine99Ticks++; + if (!gbCgbMode) + gbMemory[0xff70] = gbMemory[0xff74] = 0xff; - gbLcdModeDelayed = gbLcdMode; - gbLcdTicksDelayed = gbLcdTicks+1; - gbLcdLYIncrementTicksDelayed = gbLcdLYIncrementTicks+1; + if (gbCgbMode) + gbMemory[0xff56] = 0x3e; + else + gbMemory[0xff56] = 0xff; + register_SCY = 0; + register_SCX = 0; + register_LYC = 0; + register_DMA = 0xff; + register_WY = 0; + register_WX = 0; + register_VBK = 0; + register_HDMA1 = 0xff; + register_HDMA2 = 0xff; + register_HDMA3 = 0xff; + register_HDMA4 = 0xff; + register_HDMA5 = 0xff; + register_SVBK = 0; + register_IE = 0; - gbTimerModeChange = false; - gbTimerOnChange = false; - gbTimerOn = false; + if (gbCgbMode) + gbMemory[0xff02] = 0x7c; + else + gbMemory[0xff02] = 0x7e; - if(gbCgbMode) { - for (i = 0; i<0x20; i++) - gbPalette[i] = 0x7fff; + gbMemory[0xff03] = 0xff; + int i; + for (i = 0x8; i < 0xf; i++) + gbMemory[0xff00 + i] = 0xff; - // This is just to show that the starting values of the OBJ palettes are different - // between the 3 consoles, and that they 'kinda' stay the same at each reset - // (they can slightly change, somehow (randomly?)). - // You can check the effects of gbGBCColorType on the "Vila Caldan Color" gbc demo. - // Note that you could also check the Div register to check on which system the game - // is running (GB,GBC and GBA(SP) have different startup values). - // Unfortunatly, I don't have any SGB system, so I can't get their starting values. + gbMemory[0xff13] = 0xff; + gbMemory[0xff15] = 0xff; + gbMemory[0xff18] = 0xff; + gbMemory[0xff1d] = 0xff; + gbMemory[0xff1f] = 0xff; - if (gbGBCColorType == 0) // GBC Hardware - { - gbPalette[0x20] = 0x0600; - gbPalette[0x21] = 0xfdf3; - gbPalette[0x22] = 0x041c; - gbPalette[0x23] = 0xf5db; - gbPalette[0x24] = 0x4419; - gbPalette[0x25] = 0x57ea; - gbPalette[0x26] = 0x2808; - gbPalette[0x27] = 0x9b75; - gbPalette[0x28] = 0x129b; - gbPalette[0x29] = 0xfce0; - gbPalette[0x2a] = 0x22da; - gbPalette[0x2b] = 0x4ac5; - gbPalette[0x2c] = 0x2d71; - gbPalette[0x2d] = 0xf0c2; - gbPalette[0x2e] = 0x5137; - gbPalette[0x2f] = 0x2d41; - gbPalette[0x30] = 0x6b2d; - gbPalette[0x31] = 0x2215; - gbPalette[0x32] = 0xbe0a; - gbPalette[0x33] = 0xc053; - gbPalette[0x34] = 0xfe5f; - gbPalette[0x35] = 0xe000; - gbPalette[0x36] = 0xbe10; - gbPalette[0x37] = 0x914d; - gbPalette[0x38] = 0x7f91; - gbPalette[0x39] = 0x02b5; - gbPalette[0x3a] = 0x77ac; - gbPalette[0x3b] = 0x14e5; - gbPalette[0x3c] = 0xcf89; - gbPalette[0x3d] = 0xa03d; - gbPalette[0x3e] = 0xfd50; - gbPalette[0x3f] = 0x91ff; - } - else if (gbGBCColorType == 1) // GBA Hardware - { - gbPalette[0x20] = 0xbe00; - gbPalette[0x21] = 0xfdfd; - gbPalette[0x22] = 0xbd69; - gbPalette[0x23] = 0x7baf; - gbPalette[0x24] = 0xf5ff; - gbPalette[0x25] = 0x3f8f; - gbPalette[0x26] = 0xcee5; - gbPalette[0x27] = 0x5bf7; - gbPalette[0x28] = 0xb35b; - gbPalette[0x29] = 0xef97; - gbPalette[0x2a] = 0xef9f; - gbPalette[0x2b] = 0x97f7; - gbPalette[0x2c] = 0x82bf; - gbPalette[0x2d] = 0x9f3d; - gbPalette[0x2e] = 0xddde; - gbPalette[0x2f] = 0xbad5; - gbPalette[0x30] = 0x3cba; - gbPalette[0x31] = 0xdfd7; - gbPalette[0x32] = 0xedea; - gbPalette[0x33] = 0xfeda; - gbPalette[0x34] = 0xf7f9; - gbPalette[0x35] = 0xfdee; - gbPalette[0x36] = 0x6d2f; - gbPalette[0x37] = 0xf0e6; - gbPalette[0x38] = 0xf7f0; - gbPalette[0x39] = 0xf296; - gbPalette[0x3a] = 0x3bf1; - gbPalette[0x3b] = 0xe211; - gbPalette[0x3c] = 0x69ba; - gbPalette[0x3d] = 0x3d0d; - gbPalette[0x3e] = 0xdfd3; - gbPalette[0x3f] = 0xa6ba; - } - else if (gbGBCColorType == 2) // GBASP Hardware - { - gbPalette[0x20] = 0x9c00; - gbPalette[0x21] = 0x6340; - gbPalette[0x22] = 0x10c6; - gbPalette[0x23] = 0xdb97; - gbPalette[0x24] = 0x7622; - gbPalette[0x25] = 0x3e57; - gbPalette[0x26] = 0x2e12; - gbPalette[0x27] = 0x95c3; - gbPalette[0x28] = 0x1095; - gbPalette[0x29] = 0x488c; - gbPalette[0x2a] = 0x8241; - gbPalette[0x2b] = 0xde8c; - gbPalette[0x2c] = 0xfabc; - gbPalette[0x2d] = 0x0e81; - gbPalette[0x2e] = 0x7675; - gbPalette[0x2f] = 0xfdec; - gbPalette[0x30] = 0xddfd; - gbPalette[0x31] = 0x5995; - gbPalette[0x32] = 0x066a; - gbPalette[0x33] = 0xed1e; - gbPalette[0x34] = 0x1e84; - gbPalette[0x35] = 0x1d14; - gbPalette[0x36] = 0x11c3; - gbPalette[0x37] = 0x2749; - gbPalette[0x38] = 0xa727; - gbPalette[0x39] = 0x6266; - gbPalette[0x3a] = 0xe27b; - gbPalette[0x3b] = 0xe3fc; - gbPalette[0x3c] = 0x1f76; - gbPalette[0x3d] = 0xf158; - gbPalette[0x3e] = 0x468e; - gbPalette[0x3f] = 0xa540; + for (i = 0x27; i < 0x30; i++) + gbMemory[0xff00 + i] = 0xff; + + gbMemory[0xff4c] = 0xff; + gbMemory[0xff4e] = 0xff; + gbMemory[0xff50] = 0xff; + + for (i = 0x57; i < 0x68; i++) + gbMemory[0xff00 + i] = 0xff; + + for (i = 0x5d; i < 0x70; i++) + gbMemory[0xff00 + i] = 0xff; + + gbMemory[0xff71] = 0xff; + + for (i = 0x78; i < 0x80; i++) + gbMemory[0xff00 + i] = 0xff; + + if (gbHardware & 0xa) { + + if (gbHardware & 2) { + AF.W = 0x1180; + BC.W = 0x0000; + } else { + AF.W = 0x1100; + BC.W = 0x0100; // GBA/SP have B = 0x01 (which means GBC & GBA/SP bootrom are different !) + } + + gbMemory[0xff26] = 0xf1; + if (gbCgbMode) { + + gbMemory[0xff31] = 0xff; + gbMemory[0xff33] = 0xff; + gbMemory[0xff35] = 0xff; + gbMemory[0xff37] = 0xff; + gbMemory[0xff39] = 0xff; + gbMemory[0xff3b] = 0xff; + gbMemory[0xff3d] = 0xff; + + gbMemory[0xff44] = register_LY = 0x90; + gbDivTicks = 0x19 + ((gbHardware & 2) >> 1); + gbInternalTimer = 0x58 + ((gbHardware & 2) >> 1); + gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS - (register_LY - 0x8F) * GBLY_INCREMENT_CLOCK_TICKS + 72 + ((gbHardware & 2) >> 1); + gbLcdLYIncrementTicks = 72 + ((gbHardware & 2) >> 1); + gbMemory[0xff04] = register_DIV = 0x1E; + } else { + gbMemory[0xff44] = register_LY = 0x94; + gbDivTicks = 0x22 + ((gbHardware & 2) >> 1); + gbInternalTimer = 0x61 + ((gbHardware & 2) >> 1); + gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS - (register_LY - 0x8F) * GBLY_INCREMENT_CLOCK_TICKS + 25 + ((gbHardware & 2) >> 1); + gbLcdLYIncrementTicks = 25 + ((gbHardware & 2) >> 1); + gbMemory[0xff04] = register_DIV = 0x26; + } + + DE.W = 0xff56; + HL.W = 0x000d; + + register_HDMA5 = 0xff; + gbMemory[0xff68] = 0xc0; + gbMemory[0xff6a] = 0xc0; + + gbMemory[0xff41] = register_STAT = 0x81; + gbLcdMode = 1; + } else { + if (gbHardware & 4) { + if (gbEmulatorType == 5) + AF.W = 0xffb0; + else + AF.W = 0x01b0; + BC.W = 0x0013; + DE.W = 0x00d8; + HL.W = 0x014d; + } + gbDivTicks = 14; + gbInternalTimer = gbDivTicks--; + gbMemory[0xff04] = register_DIV = 0xAB; + gbMemory[0xff41] = register_STAT = 0x85; + gbMemory[0xff44] = register_LY = 0x00; + gbLcdTicks = 15; + gbLcdLYIncrementTicks = 114 + gbLcdTicks; + gbLcdMode = 1; } - // The CGB BIOS palette selection has to be done by VBA if BIOS is skipped. - if (!(gbRom[0x143] & 0x80) && !inBios) { - gbSelectColorizationPalette(); + // used for the handling of the gb Boot Rom + if ((gbHardware & 7) && (bios != NULL) && useBios && !skipBios) { + if (gbHardware & 5) { + memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000); + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100); + } else { + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900); + memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100); + } + gbWhiteScreen = 0; + + gbInternalTimer = 0x3e; + gbDivTicks = 0x3f; + gbMemory[0xff04] = register_DIV = 0x00; + PC.W = 0x0000; + register_LCDC = 0x11; + gbScreenOn = false; + gbLcdTicks = 0; + gbLcdMode = 0; + gbLcdModeDelayed = 0; + gbMemory[0xff41] = register_STAT &= 0xfc; + gbInt48Signal = 0; + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS; + gbMemory[0xff6c] = 0xfe; + + inBios = true; + } else if (gbHardware & 0xa) { + // Set compatibility mode if it is a DMG ROM. + gbMemory[0xff6c] = 0xfe | (uint8_t) !(gbRom[0x143] & 0x80); } - } else { - if(gbSgbMode) { - for(i = 0; i < 8; i++) - gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; + gbLine99Ticks = 1; + if (gbHardware & 8) + gbLine99Ticks++; + gbLcdModeDelayed = gbLcdMode; + gbLcdTicksDelayed = gbLcdTicks + 1; + gbLcdLYIncrementTicksDelayed = gbLcdLYIncrementTicks + 1; + + gbTimerModeChange = false; + gbTimerOnChange = false; + gbTimerOn = false; + + if (gbCgbMode) { + for (i = 0; i < 0x20; i++) + gbPalette[i] = 0x7fff; + + // This is just to show that the starting values of the OBJ palettes are different + // between the 3 consoles, and that they 'kinda' stay the same at each reset + // (they can slightly change, somehow (randomly?)). + // You can check the effects of gbGBCColorType on the "Vila Caldan Color" gbc demo. + // Note that you could also check the Div register to check on which system the game + // is running (GB,GBC and GBA(SP) have different startup values). + // Unfortunatly, I don't have any SGB system, so I can't get their starting values. + + if (gbGBCColorType == 0) // GBC Hardware + { + gbPalette[0x20] = 0x0600; + gbPalette[0x21] = 0xfdf3; + gbPalette[0x22] = 0x041c; + gbPalette[0x23] = 0xf5db; + gbPalette[0x24] = 0x4419; + gbPalette[0x25] = 0x57ea; + gbPalette[0x26] = 0x2808; + gbPalette[0x27] = 0x9b75; + gbPalette[0x28] = 0x129b; + gbPalette[0x29] = 0xfce0; + gbPalette[0x2a] = 0x22da; + gbPalette[0x2b] = 0x4ac5; + gbPalette[0x2c] = 0x2d71; + gbPalette[0x2d] = 0xf0c2; + gbPalette[0x2e] = 0x5137; + gbPalette[0x2f] = 0x2d41; + gbPalette[0x30] = 0x6b2d; + gbPalette[0x31] = 0x2215; + gbPalette[0x32] = 0xbe0a; + gbPalette[0x33] = 0xc053; + gbPalette[0x34] = 0xfe5f; + gbPalette[0x35] = 0xe000; + gbPalette[0x36] = 0xbe10; + gbPalette[0x37] = 0x914d; + gbPalette[0x38] = 0x7f91; + gbPalette[0x39] = 0x02b5; + gbPalette[0x3a] = 0x77ac; + gbPalette[0x3b] = 0x14e5; + gbPalette[0x3c] = 0xcf89; + gbPalette[0x3d] = 0xa03d; + gbPalette[0x3e] = 0xfd50; + gbPalette[0x3f] = 0x91ff; + } else if (gbGBCColorType == 1) // GBA Hardware + { + gbPalette[0x20] = 0xbe00; + gbPalette[0x21] = 0xfdfd; + gbPalette[0x22] = 0xbd69; + gbPalette[0x23] = 0x7baf; + gbPalette[0x24] = 0xf5ff; + gbPalette[0x25] = 0x3f8f; + gbPalette[0x26] = 0xcee5; + gbPalette[0x27] = 0x5bf7; + gbPalette[0x28] = 0xb35b; + gbPalette[0x29] = 0xef97; + gbPalette[0x2a] = 0xef9f; + gbPalette[0x2b] = 0x97f7; + gbPalette[0x2c] = 0x82bf; + gbPalette[0x2d] = 0x9f3d; + gbPalette[0x2e] = 0xddde; + gbPalette[0x2f] = 0xbad5; + gbPalette[0x30] = 0x3cba; + gbPalette[0x31] = 0xdfd7; + gbPalette[0x32] = 0xedea; + gbPalette[0x33] = 0xfeda; + gbPalette[0x34] = 0xf7f9; + gbPalette[0x35] = 0xfdee; + gbPalette[0x36] = 0x6d2f; + gbPalette[0x37] = 0xf0e6; + gbPalette[0x38] = 0xf7f0; + gbPalette[0x39] = 0xf296; + gbPalette[0x3a] = 0x3bf1; + gbPalette[0x3b] = 0xe211; + gbPalette[0x3c] = 0x69ba; + gbPalette[0x3d] = 0x3d0d; + gbPalette[0x3e] = 0xdfd3; + gbPalette[0x3f] = 0xa6ba; + } else if (gbGBCColorType == 2) // GBASP Hardware + { + gbPalette[0x20] = 0x9c00; + gbPalette[0x21] = 0x6340; + gbPalette[0x22] = 0x10c6; + gbPalette[0x23] = 0xdb97; + gbPalette[0x24] = 0x7622; + gbPalette[0x25] = 0x3e57; + gbPalette[0x26] = 0x2e12; + gbPalette[0x27] = 0x95c3; + gbPalette[0x28] = 0x1095; + gbPalette[0x29] = 0x488c; + gbPalette[0x2a] = 0x8241; + gbPalette[0x2b] = 0xde8c; + gbPalette[0x2c] = 0xfabc; + gbPalette[0x2d] = 0x0e81; + gbPalette[0x2e] = 0x7675; + gbPalette[0x2f] = 0xfdec; + gbPalette[0x30] = 0xddfd; + gbPalette[0x31] = 0x5995; + gbPalette[0x32] = 0x066a; + gbPalette[0x33] = 0xed1e; + gbPalette[0x34] = 0x1e84; + gbPalette[0x35] = 0x1d14; + gbPalette[0x36] = 0x11c3; + gbPalette[0x37] = 0x2749; + gbPalette[0x38] = 0xa727; + gbPalette[0x39] = 0x6266; + gbPalette[0x3a] = 0xe27b; + gbPalette[0x3b] = 0xe3fc; + gbPalette[0x3c] = 0x1f76; + gbPalette[0x3d] = 0xf158; + gbPalette[0x3e] = 0x468e; + gbPalette[0x3f] = 0xa540; + } + + // The CGB BIOS palette selection has to be done by VBA if BIOS is skipped. + if (!(gbRom[0x143] & 0x80) && !inBios) { + gbSelectColorizationPalette(); + } + + } else { + if (gbSgbMode) { + for (i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; + } + for (i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; } - for(i = 0; i < 8; i++) - gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; - } - GBTIMER_MODE_0_CLOCK_TICKS = 256; - GBTIMER_MODE_1_CLOCK_TICKS = 4; - GBTIMER_MODE_2_CLOCK_TICKS = 16; - GBTIMER_MODE_3_CLOCK_TICKS = 64; + GBTIMER_MODE_0_CLOCK_TICKS = 256; + GBTIMER_MODE_1_CLOCK_TICKS = 4; + GBTIMER_MODE_2_CLOCK_TICKS = 16; + GBTIMER_MODE_3_CLOCK_TICKS = 64; - GBLY_INCREMENT_CLOCK_TICKS = 114; - gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; - gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; - gbSerialTicks = 0; - gbSerialBits = 0; - gbSerialOn = 0; - gbWindowLine = -1; - gbTimerOn = false; - gbTimerMode = 0; - gbSpeed = 0; - gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; - - if(gbCgbMode) { + GBLY_INCREMENT_CLOCK_TICKS = 114; + gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; + gbTimerClockTicks = GBTIMER_MODE_0_CLOCK_TICKS; + gbSerialTicks = 0; + gbSerialBits = 0; + gbSerialOn = 0; + gbWindowLine = -1; + gbTimerOn = false; + gbTimerMode = 0; gbSpeed = 0; - gbHdmaOn = 0; - gbHdmaSource = 0x99d0; - gbHdmaDestination = 0x99d0; - gbVramBank = 0; - gbWramBank = 1; + gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; - } + if (gbCgbMode) { + gbSpeed = 0; + gbHdmaOn = 0; + gbHdmaSource = 0x99d0; + gbHdmaDestination = 0x99d0; + gbVramBank = 0; + gbWramBank = 1; + } - // used to clean the borders - if (gbSgbMode) - { - gbSgbResetFlag = true; - gbSgbReset(); - if (gbBorderOn) - gbSgbRenderBorder(); - gbSgbResetFlag = false; - } + // used to clean the borders + if (gbSgbMode) { + gbSgbResetFlag = true; + gbSgbReset(); + if (gbBorderOn) + gbSgbRenderBorder(); + gbSgbResetFlag = false; + } - for(i = 0; i < 4; i++) - gbBgp[i] = gbObp0[i] = gbObp1[i] = i; + for (i = 0; i < 4; i++) + gbBgp[i] = gbObp0[i] = gbObp1[i] = i; - memset(&gbDataMBC1,0, sizeof(gbDataMBC1)); - gbDataMBC1.mapperROMBank = 1; + memset(&gbDataMBC1, 0, sizeof(gbDataMBC1)); + gbDataMBC1.mapperROMBank = 1; - gbDataMBC2.mapperRAMEnable = 0; - gbDataMBC2.mapperROMBank = 1; + gbDataMBC2.mapperRAMEnable = 0; + gbDataMBC2.mapperROMBank = 1; - memset(&gbDataMBC3,0, 6 * sizeof(int)); - gbDataMBC3.mapperROMBank = 1; + memset(&gbDataMBC3, 0, 6 * sizeof(int)); + gbDataMBC3.mapperROMBank = 1; - memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); - gbDataMBC5.mapperROMBank = 1; + memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); + gbDataMBC5.mapperROMBank = 1; - memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); - gbDataHuC1.mapperROMBank = 1; + memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); + gbDataHuC1.mapperROMBank = 1; - memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); - gbDataHuC3.mapperROMBank = 1; + memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); + gbDataHuC3.mapperROMBank = 1; - memset(&gbDataTAMA5,0, 26*sizeof(int)); - gbDataTAMA5.mapperROMBank = 1; + memset(&gbDataTAMA5, 0, 26 * sizeof(int)); + gbDataTAMA5.mapperROMBank = 1; - memset(&gbDataMMM01,0, sizeof(gbDataMMM01)); - gbDataMMM01.mapperROMBank = 1; + memset(&gbDataMMM01, 0, sizeof(gbDataMMM01)); + gbDataMMM01.mapperROMBank = 1; - if (inBios) - { - gbMemoryMap[0x00] = &gbMemory[0x0000]; - } - else - { - gbMemoryMap[0x00] = &gbRom[0x0000]; - } + if (inBios) { + gbMemoryMap[0x00] = &gbMemory[0x0000]; + } else { + 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[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(); + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + gbLastTime = systemGetClock(); + gbFrameCount = 0; + + gbScreenOn = true; + gbSystemMessage = false; + + gbCheatWrite(true); // Emulates GS codes. +} + +void gbWriteSaveMBC1(const char* name) +{ + if (gbRam) { + FILE* gzFile = fopen(name, "wb"); + + if (gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + (gbRamSizeMask + 1), + gzFile); + + fclose(gzFile); + } +} + +void gbWriteSaveMBC2(const char* name) +{ + if (gbRam) { + FILE* file = fopen(name, "wb"); + + if (file == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbMemoryMap[0x0a], + 1, + 512, + file); + + fclose(file); + } +} + +void gbWriteSaveMBC3(const char* name, bool extendedSave) +{ + if (gbRam || extendedSave) { + FILE* gzFile = fopen(name, "wb"); + if (gbRam) { + + if (gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + (gbRamSizeMask + 1), + gzFile); + } + + if (extendedSave) + fwrite(&gbDataMBC3.mapperSeconds, + 1, + 10 * sizeof(int) + sizeof(time_t), + gzFile); + + fclose(gzFile); + } +} + +void gbWriteSaveMBC5(const char* name) +{ + if (gbRam) { + FILE* gzFile = fopen(name, "wb"); + + if (gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + (gbRamSizeMask + 1), + gzFile); + + fclose(gzFile); + } +} + +void gbWriteSaveMBC7(const char* name) +{ + if (gbRam) { + 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 gbWriteSaveTAMA5(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; + } + if (gbRam) + fwrite(gbRam, + 1, + (gbRamSizeMask + 1), + gzFile); + + fwrite(gbTAMA5ram, + 1, + (gbTAMA5ramSize), + gzFile); + + if (extendedSave) + fwrite(&gbDataTAMA5.mapperSeconds, + 1, + 14 * sizeof(int) + sizeof(time_t), + gzFile); + + fclose(gzFile); +} + +void gbWriteSaveMMM01(const char* name) +{ + if (gbRam) { + FILE* gzFile = fopen(name, "wb"); + + if (gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + (gbRamSizeMask + 1), + gzFile); + + fclose(gzFile); + } +} + +bool gbReadSaveMBC1(const char* name) +{ + if (gbRam) { + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) { + return false; + } + + int read = gzread(gzFile, + gbRam, + (gbRamSizeMask + 1)); + + if (read != (gbRamSizeMask + 1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + uint8_t data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if (read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + gzclose(gzFile); + return true; + } else + return false; +} + +bool gbReadSaveMBC2(const char* name) +{ + if (gbRam) { + FILE* file = fopen(name, "rb"); + + if (file == NULL) { + return false; + } + + size_t read = fread(gbMemoryMap[0x0a], + 1, + 512, + file); + + if (read != 512) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + fclose(file); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + uint8_t data[1]; + data[0] = 0; + + read = fread(&data[0], + 1, + 1, + file); + if (read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + fclose(file); + gbBatteryError = true; + return false; + } + + fclose(file); + return true; + } else + return false; +} + +bool gbReadSaveMBC3(const char* name) +{ + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) { + return false; + } + + int read = 0; + + if (gbRam) + read = gzread(gzFile, + gbRam, + (gbRamSizeMask + 1)); + else + read = (gbRamSizeMask + 1); + + bool res = true; + + if (read != (gbRamSizeMask + 1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gbBatteryError = true; + res = false; + } else if ((gbRomType == 0xf) || (gbRomType == 0x10)) { + read = gzread(gzFile, + &gbDataMBC3.mapperSeconds, + sizeof(int) * 10 + sizeof(time_t)); + + if (read != (sizeof(int) * 10 + sizeof(time_t)) && read != 0) { + systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } else if (read == 0) { + systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } else { + // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! + uint8_t data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if (read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gbBatteryError = true; + res = false; + } + } + } + + gzclose(gzFile); + return res; +} + +bool gbReadSaveMBC5(const char* name) +{ + if (gbRam) { + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) { + return false; + } + + int read = gzread(gzFile, + gbRam, + (gbRamSizeMask + 1)); + + if (read != (gbRamSizeMask + 1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + uint8_t data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if (read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + gzclose(gzFile); + return true; + } else + return false; +} + +bool gbReadSaveMBC7(const char* name) +{ + if (gbRam) { + FILE* file = fopen(name, "rb"); + + if (file == NULL) { + return false; + } + + size_t read = fread(&gbMemory[0xa000], + 1, + 256, + file); + + if (read != 256) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + fclose(file); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + uint8_t data[1]; + data[0] = 0; + + read = fread(&data[0], + 1, + 1, + file); + if (read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + fclose(file); + gbBatteryError = true; + return false; + } + + fclose(file); + return true; + } else + return false; +} + +bool gbReadSaveTAMA5(const char* name) +{ + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) { + return false; + } + + int read = 0; + + if (gbRam) + read = gzread(gzFile, + gbRam, + (gbRamSizeMask + 1)); + else + read = gbRamSizeMask; + + read += gzread(gzFile, + gbTAMA5ram, + gbTAMA5ramSize); + + bool res = true; + + if (read != (gbRamSizeMask + gbTAMA5ramSize + 1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gbBatteryError = true; + res = false; + } else { + read = gzread(gzFile, + &gbDataTAMA5.mapperSeconds, + sizeof(int) * 14 + sizeof(time_t)); + + if (read != (sizeof(int) * 14 + sizeof(time_t)) && read != 0) { + systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } else if (read == 0) { + systemMessage(MSG_FAILED_TO_READ_RTC, N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; + } else { + // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! + uint8_t data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if (read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gbBatteryError = true; + res = false; + } + } + } + + gzclose(gzFile); + return res; +} + +bool gbReadSaveMMM01(const char* name) +{ + if (gbRam) { + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) { + return false; + } + + int read = gzread(gzFile, + gbRam, + (gbRamSizeMask + 1)); + + if (read != (gbRamSizeMask + 1)) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + // Also checks if the battery file it bigger than gbRamSizeMask+1 ! + uint8_t data[1]; + data[0] = 0; + + read = gzread(gzFile, + data, + 1); + if (read > 0) { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); + gzclose(gzFile); + gbBatteryError = true; + return false; + } + + gzclose(gzFile); + return true; + } else + return false; +} + +void gbInit() +{ + gbGenFilter(); + gbSgbInit(); + + gbMemory = (uint8_t*)malloc(65536); + + pix = (uint8_t*)calloc(1, 4 * 257 * 226); + + gbLineBuffer = (uint16_t*)malloc(160 * sizeof(uint16_t)); +} + +bool gbWriteBatteryFile(const char* file, bool extendedSave) +{ + if (gbBattery) { + switch (gbRomType) { + case 0x03: + gbWriteSaveMBC1(file); + break; + case 0x06: + gbWriteSaveMBC2(file); + break; + case 0x0d: + gbWriteSaveMMM01(file); + break; + case 0x0f: + case 0x10: + gbWriteSaveMBC3(file, extendedSave); + break; + case 0x13: + case 0xfc: + gbWriteSaveMBC3(file, false); + break; + case 0x1b: + case 0x1e: + gbWriteSaveMBC5(file); + break; + case 0x22: + gbWriteSaveMBC7(file); + break; + case 0xfd: + gbWriteSaveTAMA5(file, extendedSave); + break; + case 0xff: + gbWriteSaveMBC1(file); + break; + } + } + return true; +} + +bool gbWriteBatteryFile(const char* file) +{ + if (!gbBatteryError) { + gbWriteBatteryFile(file, true); + return true; + } else + return false; +} + +bool gbReadBatteryFile(const char* file) +{ + bool res = false; + if (gbBattery) { + switch (gbRomType) { + case 0x03: + res = gbReadSaveMBC1(file); + break; + case 0x06: + res = gbReadSaveMBC2(file); + break; + case 0x0d: + res = gbReadSaveMMM01(file); + break; + case 0x0f: + case 0x10: + if (!gbReadSaveMBC3(file)) { + time(&gbDataMBC3.mapperLastTime); + struct tm* lt; + lt = localtime(&gbDataMBC3.mapperLastTime); + 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; + } + res = true; + break; + case 0x13: + case 0xfc: + res = gbReadSaveMBC3(file); + break; + case 0x1b: + case 0x1e: + res = gbReadSaveMBC5(file); + break; + case 0x22: + res = gbReadSaveMBC7(file); + break; + case 0xfd: + if (!gbReadSaveTAMA5(file)) { + uint8_t gbDaysinMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + time(&gbDataTAMA5.mapperLastTime); + struct tm* lt; + lt = localtime(&gbDataTAMA5.mapperLastTime); + gbDataTAMA5.mapperSeconds = lt->tm_sec; + gbDataTAMA5.mapperMinutes = lt->tm_min; + gbDataTAMA5.mapperHours = lt->tm_hour; + gbDataTAMA5.mapperDays = 1; + gbDataTAMA5.mapperMonths = 1; + gbDataTAMA5.mapperYears = 1970; + int days = lt->tm_yday + 365 * 3; + while (days) { + gbDataTAMA5.mapperDays++; + days--; + if (gbDataTAMA5.mapperDays > gbDaysinMonth[gbDataTAMA5.mapperMonths - 1]) { + gbDataTAMA5.mapperDays = 1; + gbDataTAMA5.mapperMonths++; + if (gbDataTAMA5.mapperMonths > 12) { + gbDataTAMA5.mapperMonths = 1; + gbDataTAMA5.mapperYears++; + if ((gbDataTAMA5.mapperYears & 3) == 0) + gbDaysinMonth[1] = 29; + else + gbDaysinMonth[1] = 28; + } + } + } + gbDataTAMA5.mapperControl = (gbDataTAMA5.mapperControl & 0xfe) | (lt->tm_yday > 255 ? 1 : 0); + res = false; + break; + } + res = true; + break; + case 0xff: + res = gbReadSaveMBC1(file); + break; + } + } + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + return res; +} + +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; + } + + 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); + size_t read = 0; + int toRead = 0; + switch (gbRomType) { + case 0x03: + case 0x0f: + case 0x10: + case 0x13: + case 0x1b: + case 0x1e: + case 0xff: + read = fread(gbRam, 1, (gbRamSizeMask + 1), file); + toRead = (gbRamSizeMask + 1); + 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(uint16_t) }, + { &SP.W, sizeof(uint16_t) }, + { &AF.W, sizeof(uint16_t) }, + { &BC.W, sizeof(uint16_t) }, + { &DE.W, sizeof(uint16_t) }, + { &HL.W, sizeof(uint16_t) }, + { &IFF, sizeof(uint8_t) }, + { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int) }, + { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int) }, + { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int) }, + { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int) }, + { &GBDIV_CLOCK_TICKS, sizeof(int) }, + { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int) }, + { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int) }, + { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int) }, + { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int) }, + { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int) }, + { &GBSERIAL_CLOCK_TICKS, sizeof(int) }, + { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int) }, + { &gbDivTicks, sizeof(int) }, + { &gbLcdMode, sizeof(int) }, + { &gbLcdTicks, sizeof(int) }, + { &gbLcdLYIncrementTicks, sizeof(int) }, + { &gbTimerTicks, sizeof(int) }, + { &gbTimerClockTicks, sizeof(int) }, + { &gbSerialTicks, sizeof(int) }, + { &gbSerialBits, sizeof(int) }, + { &gbInt48Signal, sizeof(int) }, + { &gbInterruptWait, sizeof(int) }, + { &gbSynchronizeTicks, sizeof(int) }, + { &gbTimerOn, sizeof(int) }, + { &gbTimerMode, sizeof(int) }, + { &gbSerialOn, sizeof(int) }, + { &gbWindowLine, sizeof(int) }, + { &gbCgbMode, sizeof(int) }, + { &gbVramBank, sizeof(int) }, + { &gbWramBank, sizeof(int) }, + { &gbHdmaSource, sizeof(int) }, + { &gbHdmaDestination, sizeof(int) }, + { &gbHdmaBytes, sizeof(int) }, + { &gbHdmaOn, sizeof(int) }, + { &gbSpeed, sizeof(int) }, + { &gbSgbMode, sizeof(int) }, + { ®ister_DIV, sizeof(uint8_t) }, + { ®ister_TIMA, sizeof(uint8_t) }, + { ®ister_TMA, sizeof(uint8_t) }, + { ®ister_TAC, sizeof(uint8_t) }, + { ®ister_IF, sizeof(uint8_t) }, + { ®ister_LCDC, sizeof(uint8_t) }, + { ®ister_STAT, sizeof(uint8_t) }, + { ®ister_SCY, sizeof(uint8_t) }, + { ®ister_SCX, sizeof(uint8_t) }, + { ®ister_LY, sizeof(uint8_t) }, + { ®ister_LYC, sizeof(uint8_t) }, + { ®ister_DMA, sizeof(uint8_t) }, + { ®ister_WY, sizeof(uint8_t) }, + { ®ister_WX, sizeof(uint8_t) }, + { ®ister_VBK, sizeof(uint8_t) }, + { ®ister_HDMA1, sizeof(uint8_t) }, + { ®ister_HDMA2, sizeof(uint8_t) }, + { ®ister_HDMA3, sizeof(uint8_t) }, + { ®ister_HDMA4, sizeof(uint8_t) }, + { ®ister_HDMA5, sizeof(uint8_t) }, + { ®ister_SVBK, sizeof(uint8_t) }, + { ®ister_IE, sizeof(uint8_t) }, + { &gbBgp[0], sizeof(uint8_t) }, + { &gbBgp[1], sizeof(uint8_t) }, + { &gbBgp[2], sizeof(uint8_t) }, + { &gbBgp[3], sizeof(uint8_t) }, + { &gbObp0[0], sizeof(uint8_t) }, + { &gbObp0[1], sizeof(uint8_t) }, + { &gbObp0[2], sizeof(uint8_t) }, + { &gbObp0[3], sizeof(uint8_t) }, + { &gbObp1[0], sizeof(uint8_t) }, + { &gbObp1[1], sizeof(uint8_t) }, + { &gbObp1[2], sizeof(uint8_t) }, + { &gbObp1[3], sizeof(uint8_t) }, + { NULL, 0 } +}; + +static bool gbWriteSaveState(gzFile gzFile) +{ + + utilWriteInt(gzFile, GBSAVE_GAME_VERSION); + + utilGzWrite(gzFile, &gbRom[0x134], 15); + + utilWriteInt(gzFile, useBios); + utilWriteInt(gzFile, inBios); + + utilWriteData(gzFile, gbSaveGameStruct); + + utilGzWrite(gzFile, &IFF, 2); + + if (gbSgbMode) { + gbSgbSaveGame(gzFile); + } + + utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); + utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); + utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); + utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); + utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); + utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); + utilGzWrite(gzFile, &gbDataTAMA5, sizeof(gbDataTAMA5)); + if (gbTAMA5ram != NULL) + utilGzWrite(gzFile, gbTAMA5ram, gbTAMA5ramSize); + utilGzWrite(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); + + utilGzWrite(gzFile, gbPalette, 128 * sizeof(uint16_t)); + + utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); + + if (gbRamSize && gbRam) { + utilWriteInt(gzFile, gbRamSize); + utilGzWrite(gzFile, gbRam, gbRamSize); + } + + if (gbCgbMode) { + utilGzWrite(gzFile, gbVram, 0x4000); + utilGzWrite(gzFile, gbWram, 0x8000); + } + + gbSoundSaveGame(gzFile); + + gbCheatsSaveGame(gzFile); + + utilWriteInt(gzFile, gbLcdModeDelayed); + utilWriteInt(gzFile, gbLcdTicksDelayed); + utilWriteInt(gzFile, gbLcdLYIncrementTicksDelayed); + utilWriteInt(gzFile, gbSpritesTicks[299]); + utilWriteInt(gzFile, gbTimerModeChange); + utilWriteInt(gzFile, gbTimerOnChange); + utilWriteInt(gzFile, gbHardware); + utilWriteInt(gzFile, gbBlackScreen); + utilWriteInt(gzFile, oldRegister_WY); + utilWriteInt(gzFile, gbWindowLine); + utilWriteInt(gzFile, inUseRegister_WY); + utilWriteInt(gzFile, gbScreenOn); + utilWriteInt(gzFile, 0x12345678); // end marker + return true; +} + +bool gbWriteMemSaveState(char* memory, int available, long& reserved) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "w"); + + if (gzFile == NULL) { + return false; + } + + bool res = gbWriteSaveState(gzFile); + + reserved = utilGzMemTell(gzFile) + 8; + + if (reserved >= (available)) + res = false; + + utilGzClose(gzFile); + + return res; +} + +bool gbWriteSaveState(const char* name) +{ + gzFile gzFile = utilGzOpen(name, "wb"); + + if (gzFile == NULL) + return false; + + bool res = gbWriteSaveState(gzFile); + + utilGzClose(gzFile); + return res; +} + +static bool gbReadSaveState(gzFile gzFile) +{ + int version = utilReadInt(gzFile); + + if (version > GBSAVE_GAME_VERSION || version < 0) { + systemMessage(MSG_UNSUPPORTED_VB_SGM, + N_("Unsupported VisualBoy save game version %d"), version); + return false; + } + + uint8_t 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]); + return false; + } + + bool ub = false; + bool ib = false; + + if (version >= 11) { + ub = utilReadInt(gzFile) ? true : false; + ib = utilReadInt(gzFile) ? true : false; + + if ((ub != useBios) && (ib)) { + if (useBios) + systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, + N_("Save game is not using the BIOS files")); + else + systemMessage(MSG_SAVE_GAME_USING_BIOS, + N_("Save game is using the BIOS file")); + return false; + } + } + + gbReset(); + + inBios = ib; + + utilReadData(gzFile, gbSaveGameStruct); + + // Correct crash when loading color gameboy save in regular gameboy type. + if (!gbCgbMode) { + if (gbVram != NULL) { + free(gbVram); + gbVram = NULL; + } + if (gbWram != NULL) { + free(gbWram); + gbWram = NULL; + } + } else { + if (gbVram == NULL) + gbVram = (uint8_t*)malloc(0x4000); + if (gbWram == NULL) + gbWram = (uint8_t*)malloc(0x8000); + memset(gbVram, 0, 0x4000); + memset(gbPalette, 0, 2 * 128); + } + + 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 + } + if (version < 11) + utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1) - sizeof(int)); + else + 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(gbDataMBC3) - sizeof(time_t)); + else + utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); + utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); + utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); + utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); + if (version >= 11) { + utilGzRead(gzFile, &gbDataTAMA5, sizeof(gbDataTAMA5)); + if (gbTAMA5ram != NULL) { + if (skipSaveGameBattery) { + utilGzSeek(gzFile, gbTAMA5ramSize, SEEK_CUR); + } else { + utilGzRead(gzFile, gbTAMA5ram, gbTAMA5ramSize); + } + } + utilGzRead(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); + } + + if (version < GBSAVE_GAME_VERSION_5) { + utilGzRead(gzFile, pix, 256 * 224 * sizeof(uint16_t)); + } + memset(pix, 0, 257 * 226 * sizeof(uint32_t)); + + if (version < GBSAVE_GAME_VERSION_6) { + utilGzRead(gzFile, gbPalette, 64 * sizeof(uint16_t)); + } else + utilGzRead(gzFile, gbPalette, 128 * sizeof(uint16_t)); + + if (version < 11) + utilGzRead(gzFile, gbPalette, 128 * sizeof(uint16_t)); + + 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) { + if (version < 11) + if (skipSaveGameBattery) { + utilGzSeek(gzFile, gbRamSize, SEEK_CUR); //skip + } else { + utilGzRead(gzFile, gbRam, gbRamSize); //read + } + else { + int ramSize = utilReadInt(gzFile); + if (skipSaveGameBattery) { + utilGzSeek(gzFile, (gbRamSize > ramSize) ? ramSize : gbRamSize, SEEK_CUR); //skip + } else { + utilGzRead(gzFile, gbRam, (gbRamSize > ramSize) ? ramSize : gbRamSize); //read + } + if (ramSize > gbRamSize) + utilGzSeek(gzFile, ramSize - gbRamSize, SEEK_CUR); + } + } + + memset(gbSCYLine, register_SCY, sizeof(gbSCYLine)); + memset(gbSCXLine, register_SCX, sizeof(gbSCXLine)); + memset(gbBgpLine, (gbBgp[0] | (gbBgp[1] << 2) | (gbBgp[2] << 4) | (gbBgp[3] << 6)), sizeof(gbBgpLine)); + memset(gbObp0Line, (gbObp0[0] | (gbObp0[1] << 2) | (gbObp0[2] << 4) | (gbObp0[3] << 6)), sizeof(gbObp0Line)); + memset(gbObp1Line, (gbObp1[0] | (gbObp1[1] << 2) | (gbObp1[2] << 4) | (gbObp1[3] << 6)), sizeof(gbObp1Line)); + memset(gbSpritesTicks, 0x0, sizeof(gbSpritesTicks)); + + if (inBios) { + gbMemoryMap[0x00] = &gbMemory[0x0000]; + if (gbHardware & 5) { + memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000); + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100); + } else if (gbHardware & 2) { + memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900); + memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100); + } + + } else + 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]; @@ -3043,1494 +3886,377 @@ void gbReset() gbMemoryMap[0x0d] = &gbMemory[0xd000]; gbMemoryMap[0x0e] = &gbMemory[0xe000]; gbMemoryMap[0x0f] = &gbMemory[0xf000]; - } - if(gbRam) { - gbMemoryMap[0x0a] = &gbRam[0x0000]; - gbMemoryMap[0x0b] = &gbRam[0x1000]; - } - - gbSoundReset(); - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - gbLastTime = systemGetClock(); - gbFrameCount = 0; - - gbScreenOn = true; - gbSystemMessage = false; - - gbCheatWrite(true); // Emulates GS codes. - -} - -void gbWriteSaveMBC1(const char * name) -{ - if (gbRam) - { - FILE *gzFile = fopen(name,"wb"); - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - - fclose(gzFile); - } -} - -void gbWriteSaveMBC2(const char * name) -{ - if (gbRam) - { - FILE *file = fopen(name, "wb"); - - if(file == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbMemoryMap[0x0a], - 1, - 512, - file); - - fclose(file); - } -} - -void gbWriteSaveMBC3(const char * name, bool extendedSave) -{ - if (gbRam || extendedSave) - { - FILE *gzFile = fopen(name,"wb"); - if (gbRam) - { - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - } - - if(extendedSave) - fwrite(&gbDataMBC3.mapperSeconds, - 1, - 10*sizeof(int) + sizeof(time_t), - gzFile); - - fclose(gzFile); - } -} - -void gbWriteSaveMBC5(const char * name) -{ - if (gbRam) - { - FILE *gzFile = fopen(name,"wb"); - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - - fclose(gzFile); - } -} - -void gbWriteSaveMBC7(const char * name) -{ - if (gbRam) - { - 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 gbWriteSaveTAMA5(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; - } - if (gbRam) - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - - fwrite(gbTAMA5ram, - 1, - (gbTAMA5ramSize), - gzFile); - - if(extendedSave) - fwrite(&gbDataTAMA5.mapperSeconds, - 1, - 14*sizeof(int) + sizeof(time_t), - gzFile); - - fclose(gzFile); -} - -void gbWriteSaveMMM01(const char * name) -{ - if (gbRam) - { - FILE *gzFile = fopen(name,"wb"); - - if(gzFile == NULL) { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - (gbRamSizeMask+1), - gzFile); - - fclose(gzFile); - } -} - - -bool gbReadSaveMBC1(const char * name) -{ - if (gbRam) - { - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - - if(read != (gbRamSizeMask+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - uint8_t data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - gzclose(gzFile); - return true; - } - else - return false; -} - - -bool gbReadSaveMBC2(const char * name) -{ - if (gbRam) - { - FILE *file = fopen(name, "rb"); - - if(file == NULL) { - return false; - } - - size_t read = fread(gbMemoryMap[0x0a], - 1, - 512, - file); - - if(read != 512) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - fclose(file); - gbBatteryError = true; - return false; - } - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - uint8_t data[1]; - data[0] = 0; - - read = fread(&data[0], - 1, - 1, - file); - if(read > 0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - fclose(file); - gbBatteryError = true; - return false; - } - - fclose(file); - return true; - } - else - return false; -} - -bool gbReadSaveMBC3(const char * name) -{ - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = 0; - - if (gbRam) - read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - else - read = (gbRamSizeMask+1); - - - bool res = true; - - if(read != (gbRamSizeMask+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gbBatteryError = true; - res = false; - } else if ((gbRomType == 0xf) || (gbRomType == 0x10)){ - read = gzread(gzFile, - &gbDataMBC3.mapperSeconds, - sizeof(int)*10 + sizeof(time_t)); - - if(read != (sizeof(int)*10 + sizeof(time_t)) && read != 0) { - systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - else if (read == 0) - { - systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - else - { - // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! - uint8_t data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gbBatteryError = true; - res = false; - } - } - } - - gzclose(gzFile); - return res; -} - -bool gbReadSaveMBC5(const char * name) -{ - if (gbRam) - { - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - - if(read != (gbRamSizeMask+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - uint8_t data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - gzclose(gzFile); - return true; - } - else - return false; -} - -bool gbReadSaveMBC7(const char * name) -{ - if (gbRam) - { - FILE *file = fopen(name, "rb"); - - if(file == NULL) { - return false; - } - - size_t read = fread(&gbMemory[0xa000], - 1, - 256, - file); - - if(read != 256) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - fclose(file); - gbBatteryError = true; - return false; - } - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - uint8_t data[1]; - data[0] = 0; - - read = fread(&data[0], - 1, - 1, - file); - if(read > 0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - fclose(file); - gbBatteryError = true; - return false; - } - - fclose(file); - return true; - } - else - return false; -} - -bool gbReadSaveTAMA5(const char * name) -{ - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = 0; - - if (gbRam) - read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - else - read = gbRamSizeMask; - - read += gzread(gzFile, - gbTAMA5ram, - gbTAMA5ramSize); - - bool res = true; - - if(read != (gbRamSizeMask+gbTAMA5ramSize+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gbBatteryError = true; - res = false; - } else { - read = gzread(gzFile, - &gbDataTAMA5.mapperSeconds, - sizeof(int)*14 + sizeof(time_t)); - - if(read != (sizeof(int)*14 + sizeof(time_t)) && read != 0) { - systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - else if (read == 0) - { - systemMessage(MSG_FAILED_TO_READ_RTC,N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - else - { - // Also checks if the battery file it bigger than gbRamSizeMask+1+RTC ! - uint8_t data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gbBatteryError = true; - res = false; - } - } - } - - gzclose(gzFile); - return res; -} - - -bool gbReadSaveMMM01(const char * name) -{ - if (gbRam) - { - gzFile gzFile = gzopen(name, "rb"); - - if(gzFile == NULL) { - return false; - } - - int read = gzread(gzFile, - gbRam, - (gbRamSizeMask+1)); - - if(read != (gbRamSizeMask+1)) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - // Also checks if the battery file it bigger than gbRamSizeMask+1 ! - uint8_t data[1]; - data[0] = 0; - - read = gzread(gzFile, - data, - 1); - if(read >0) { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Battery file's size incompatible with the rom settings %s (%d).\nWarning : save of the battery file is now disabled !"), name, read); - gzclose(gzFile); - gbBatteryError = true; - return false; - } - - gzclose(gzFile); - return true; - } - else - return false; -} - -void gbInit() -{ - gbGenFilter(); - gbSgbInit(); - - gbMemory = (uint8_t *)malloc(65536); - - pix = (uint8_t *)calloc(1,4*257*226); - - gbLineBuffer = (uint16_t *)malloc(160 * sizeof(uint16_t)); -} - -bool gbWriteBatteryFile(const char *file, bool extendedSave) -{ - if(gbBattery) { - switch(gbRomType) { + switch (gbRomType) { + case 0x00: + case 0x01: + case 0x02: case 0x03: - gbWriteSaveMBC1(file); - break; - case 0x06: - gbWriteSaveMBC2(file); - break; - case 0x0d: - gbWriteSaveMMM01(file); - break; - case 0x0f: - case 0x10: - gbWriteSaveMBC3(file, extendedSave); - break; - case 0x13: - case 0xfc: - gbWriteSaveMBC3(file, false); - break; - case 0x1b: - case 0x1e: - gbWriteSaveMBC5(file); - break; - case 0x22: - gbWriteSaveMBC7(file); - break; - case 0xfd: - gbWriteSaveTAMA5(file, extendedSave); - break; - case 0xff: - gbWriteSaveMBC1(file); - break; - } - } - return true; -} - -bool gbWriteBatteryFile(const char *file) -{ - if (!gbBatteryError) - { - gbWriteBatteryFile(file, true); - return true; - } - else return false; -} - -bool gbReadBatteryFile(const char *file) -{ - bool res = false; - if(gbBattery) { - switch(gbRomType) { - case 0x03: - res = gbReadSaveMBC1(file); - break; - case 0x06: - res = gbReadSaveMBC2(file); - break; - case 0x0d: - res = gbReadSaveMMM01(file); - break; - case 0x0f: - case 0x10: - if(!gbReadSaveMBC3(file)) { - time(&gbDataMBC3.mapperLastTime); - struct tm *lt; - lt = localtime(&gbDataMBC3.mapperLastTime); - 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; + // MBC 1 + memoryUpdateMapMBC1(); break; - } - res = true; - break; + case 0x05: + case 0x06: + // MBC2 + memoryUpdateMapMBC2(); + break; + case 0x0b: + case 0x0c: + case 0x0d: + // MMM01 + memoryUpdateMapMMM01(); + break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: case 0x13: - case 0xfc: - res = gbReadSaveMBC3(file); - break; + // MBC 3 + memoryUpdateMapMBC3(); + break; + case 0x19: + case 0x1a: case 0x1b: + // MBC5 + memoryUpdateMapMBC5(); + break; + case 0x1c: + case 0x1d: case 0x1e: - res = gbReadSaveMBC5(file); - break; + // MBC 5 Rumble + memoryUpdateMapMBC5(); + break; case 0x22: - res = gbReadSaveMBC7(file); - break; + // MBC 7 + memoryUpdateMapMBC7(); + break; + case 0x56: + // GS3 + memoryUpdateMapGS3(); + break; case 0xfd: - if(!gbReadSaveTAMA5(file)) { - uint8_t gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - time(&gbDataTAMA5.mapperLastTime); - struct tm *lt; - lt = localtime(&gbDataTAMA5.mapperLastTime); - gbDataTAMA5.mapperSeconds = lt->tm_sec; - gbDataTAMA5.mapperMinutes = lt->tm_min; - gbDataTAMA5.mapperHours = lt->tm_hour; - gbDataTAMA5.mapperDays = 1; - gbDataTAMA5.mapperMonths = 1; - gbDataTAMA5.mapperYears = 1970; - int days = lt->tm_yday+365*3; - while (days) - { - gbDataTAMA5.mapperDays++; - days--; - if (gbDataTAMA5.mapperDays>gbDaysinMonth[gbDataTAMA5.mapperMonths-1]) - { - gbDataTAMA5.mapperDays = 1; - gbDataTAMA5.mapperMonths++; - if (gbDataTAMA5.mapperMonths>12) - { - gbDataTAMA5.mapperMonths = 1; - gbDataTAMA5.mapperYears++; - if ((gbDataTAMA5.mapperYears & 3) == 0) - gbDaysinMonth[1] = 29; - else - gbDaysinMonth[1] = 28; - } - } + // TAMA5 + memoryUpdateMapTAMA5(); + break; + case 0xfe: + // HuC3 + memoryUpdateMapHuC3(); + break; + case 0xff: + // HuC1 + memoryUpdateMapHuC1(); + break; + } + + if (gbCgbMode) { + 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]; + } + + gbSoundReadGame(version, gzFile); + + if (gbCgbMode && gbSgbMode) { + gbSgbMode = 0; + } + + if (gbBorderOn && !gbSgbMask) { + gbSgbRenderBorder(); + } + + systemDrawScreen(); + + if (version > GBSAVE_GAME_VERSION_1) { + if (skipSaveGameCheats) { + gbCheatsReadGameSkip(gzFile, version); + } else { + gbCheatsReadGame(gzFile, version); } - gbDataTAMA5.mapperControl = (gbDataTAMA5.mapperControl & 0xfe) | - (lt->tm_yday > 255 ? 1: 0); - res = false; - break; - } - res = true; - break; - case 0xff: - res = gbReadSaveMBC1(file); - break; - } - } - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - return res; -} - -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; - } - - 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); - size_t read = 0; - int toRead = 0; - switch(gbRomType) { - case 0x03: - case 0x0f: - case 0x10: - case 0x13: - case 0x1b: - case 0x1e: - case 0xff: - read = fread(gbRam, 1, (gbRamSizeMask+1), file); - toRead = (gbRamSizeMask+1); - 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(uint16_t) }, - { &SP.W, sizeof(uint16_t) }, - { &AF.W, sizeof(uint16_t) }, - { &BC.W, sizeof(uint16_t) }, - { &DE.W, sizeof(uint16_t) }, - { &HL.W, sizeof(uint16_t) }, - { &IFF, sizeof(uint8_t) }, - { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int) }, - { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int) }, - { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int) }, - { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int) }, - { &GBDIV_CLOCK_TICKS, sizeof(int) }, - { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int) }, - { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int) }, - { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int) }, - { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int) }, - { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int) }, - { &GBSERIAL_CLOCK_TICKS, sizeof(int) }, - { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int) }, - { &gbDivTicks, sizeof(int) }, - { &gbLcdMode, sizeof(int) }, - { &gbLcdTicks, sizeof(int) }, - { &gbLcdLYIncrementTicks, sizeof(int) }, - { &gbTimerTicks, sizeof(int) }, - { &gbTimerClockTicks, sizeof(int) }, - { &gbSerialTicks, sizeof(int) }, - { &gbSerialBits, sizeof(int) }, - { &gbInt48Signal, sizeof(int) }, - { &gbInterruptWait, sizeof(int) }, - { &gbSynchronizeTicks, sizeof(int) }, - { &gbTimerOn, sizeof(int) }, - { &gbTimerMode, sizeof(int) }, - { &gbSerialOn, sizeof(int) }, - { &gbWindowLine, sizeof(int) }, - { &gbCgbMode, sizeof(int) }, - { &gbVramBank, sizeof(int) }, - { &gbWramBank, sizeof(int) }, - { &gbHdmaSource, sizeof(int) }, - { &gbHdmaDestination, sizeof(int) }, - { &gbHdmaBytes, sizeof(int) }, - { &gbHdmaOn, sizeof(int) }, - { &gbSpeed, sizeof(int) }, - { &gbSgbMode, sizeof(int) }, - { ®ister_DIV, sizeof(uint8_t) }, - { ®ister_TIMA, sizeof(uint8_t) }, - { ®ister_TMA, sizeof(uint8_t) }, - { ®ister_TAC, sizeof(uint8_t) }, - { ®ister_IF, sizeof(uint8_t) }, - { ®ister_LCDC, sizeof(uint8_t) }, - { ®ister_STAT, sizeof(uint8_t) }, - { ®ister_SCY, sizeof(uint8_t) }, - { ®ister_SCX, sizeof(uint8_t) }, - { ®ister_LY, sizeof(uint8_t) }, - { ®ister_LYC, sizeof(uint8_t) }, - { ®ister_DMA, sizeof(uint8_t) }, - { ®ister_WY, sizeof(uint8_t) }, - { ®ister_WX, sizeof(uint8_t) }, - { ®ister_VBK, sizeof(uint8_t) }, - { ®ister_HDMA1, sizeof(uint8_t) }, - { ®ister_HDMA2, sizeof(uint8_t) }, - { ®ister_HDMA3, sizeof(uint8_t) }, - { ®ister_HDMA4, sizeof(uint8_t) }, - { ®ister_HDMA5, sizeof(uint8_t) }, - { ®ister_SVBK, sizeof(uint8_t) }, - { ®ister_IE , sizeof(uint8_t) }, - { &gbBgp[0], sizeof(uint8_t) }, - { &gbBgp[1], sizeof(uint8_t) }, - { &gbBgp[2], sizeof(uint8_t) }, - { &gbBgp[3], sizeof(uint8_t) }, - { &gbObp0[0], sizeof(uint8_t) }, - { &gbObp0[1], sizeof(uint8_t) }, - { &gbObp0[2], sizeof(uint8_t) }, - { &gbObp0[3], sizeof(uint8_t) }, - { &gbObp1[0], sizeof(uint8_t) }, - { &gbObp1[1], sizeof(uint8_t) }, - { &gbObp1[2], sizeof(uint8_t) }, - { &gbObp1[3], sizeof(uint8_t) }, - { NULL, 0 } -}; - - -static bool gbWriteSaveState(gzFile gzFile) -{ - - utilWriteInt(gzFile, GBSAVE_GAME_VERSION); - - utilGzWrite(gzFile, &gbRom[0x134], 15); - - utilWriteInt(gzFile, useBios); - utilWriteInt(gzFile, inBios); - - utilWriteData(gzFile, gbSaveGameStruct); - - utilGzWrite(gzFile, &IFF, 2); - - if(gbSgbMode) { - gbSgbSaveGame(gzFile); - } - - utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); - utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); - utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); - utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); - utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); - utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); - utilGzWrite(gzFile, &gbDataTAMA5, sizeof(gbDataTAMA5)); - if (gbTAMA5ram != NULL) - utilGzWrite(gzFile, gbTAMA5ram, gbTAMA5ramSize); - utilGzWrite(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); - - utilGzWrite(gzFile, gbPalette, 128 * sizeof(uint16_t)); - - utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); - - if(gbRamSize && gbRam) { - utilWriteInt(gzFile, gbRamSize); - utilGzWrite(gzFile, gbRam, gbRamSize); - } - - if(gbCgbMode) { - utilGzWrite(gzFile, gbVram, 0x4000); - utilGzWrite(gzFile, gbWram, 0x8000); - } - - gbSoundSaveGame(gzFile); - - gbCheatsSaveGame(gzFile); - - utilWriteInt(gzFile, gbLcdModeDelayed); - utilWriteInt(gzFile, gbLcdTicksDelayed); - utilWriteInt(gzFile, gbLcdLYIncrementTicksDelayed); - utilWriteInt(gzFile, gbSpritesTicks[299]); - utilWriteInt(gzFile, gbTimerModeChange); - utilWriteInt(gzFile, gbTimerOnChange); - utilWriteInt(gzFile, gbHardware); - utilWriteInt(gzFile, gbBlackScreen); - utilWriteInt(gzFile, oldRegister_WY); - utilWriteInt(gzFile, gbWindowLine); - utilWriteInt(gzFile, inUseRegister_WY); - utilWriteInt(gzFile, gbScreenOn); - utilWriteInt(gzFile, 0x12345678); // end marker - return true; -} - -bool gbWriteMemSaveState(char *memory, int available, long& reserved) -{ - gzFile gzFile = utilMemGzOpen(memory, available, "w"); - - if(gzFile == NULL) { - return false; - } - - bool res = gbWriteSaveState(gzFile); - - reserved = utilGzMemTell(gzFile)+8; - - if(reserved >= (available)) - res = false; - - utilGzClose(gzFile); - - return res; -} - -bool gbWriteSaveState(const char *name) -{ - gzFile gzFile = utilGzOpen(name,"wb"); - - if(gzFile == NULL) - return false; - - bool res = gbWriteSaveState(gzFile); - - utilGzClose(gzFile); - return res; -} - -static bool gbReadSaveState(gzFile gzFile) -{ - int version = utilReadInt(gzFile); - - if(version > GBSAVE_GAME_VERSION || version < 0) { - systemMessage(MSG_UNSUPPORTED_VB_SGM, - N_("Unsupported VisualBoy save game version %d"), version); - return false; - } - - uint8_t 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]); - return false; - } - - - bool ub = false; - bool ib = false; - - if (version >= 11) - { - ub = utilReadInt(gzFile) ? true : false; - ib = utilReadInt(gzFile) ? true : false; - - if((ub != useBios) && (ib)) { - if(useBios) - systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, - N_("Save game is not using the BIOS files")); - else - systemMessage(MSG_SAVE_GAME_USING_BIOS, - N_("Save game is using the BIOS file")); - return false; - } - } - - gbReset(); - - inBios = ib; - - utilReadData(gzFile, gbSaveGameStruct); - - - // Correct crash when loading color gameboy save in regular gameboy type. - if (!gbCgbMode) - { - if(gbVram != NULL) { - free(gbVram); - gbVram = NULL; - } - if(gbWram != NULL) { - free(gbWram); - gbWram = NULL; - } - } - else - { - if(gbVram == NULL) - gbVram = (uint8_t *)malloc(0x4000); - if(gbWram == NULL) - gbWram = (uint8_t *)malloc(0x8000); - memset(gbVram,0,0x4000); - memset(gbPalette,0, 2*128); - } - - - - 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 - } - if (version<11) - utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1) - sizeof(int)); - else - 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(gbDataMBC3)-sizeof(time_t)); - else - utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); - utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); - utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); - utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); - if(version>=11) - { - utilGzRead(gzFile, &gbDataTAMA5, sizeof(gbDataTAMA5)); - if(gbTAMA5ram != NULL) { - if(skipSaveGameBattery) { - utilGzSeek(gzFile, gbTAMA5ramSize, SEEK_CUR); - } else { - utilGzRead(gzFile, gbTAMA5ram, gbTAMA5ramSize); - } - } - utilGzRead(gzFile, &gbDataMMM01, sizeof(gbDataMMM01)); - } - - if(version < GBSAVE_GAME_VERSION_5) { - utilGzRead(gzFile, pix, 256*224*sizeof(uint16_t)); - } - memset(pix, 0, 257*226*sizeof(uint32_t)); - - if(version < GBSAVE_GAME_VERSION_6) { - utilGzRead(gzFile, gbPalette, 64 * sizeof(uint16_t)); - } else - utilGzRead(gzFile, gbPalette, 128 * sizeof(uint16_t)); - - if (version < 11) - utilGzRead(gzFile, gbPalette, 128 * sizeof(uint16_t)); - - 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) { - if(version < 11) - if(skipSaveGameBattery) { - utilGzSeek(gzFile, gbRamSize, SEEK_CUR); //skip - } else { - utilGzRead(gzFile, gbRam, gbRamSize); //read - } - else - { - int ramSize = utilReadInt(gzFile); - if(skipSaveGameBattery) { - utilGzSeek(gzFile, (gbRamSize>ramSize) ? ramSize : gbRamSize, SEEK_CUR); //skip - } else { - utilGzRead(gzFile, gbRam, (gbRamSize>ramSize) ? ramSize : gbRamSize); //read - } - if(ramSize>gbRamSize) - utilGzSeek(gzFile,ramSize-gbRamSize,SEEK_CUR); - } - } - - memset(gbSCYLine, register_SCY, sizeof(gbSCYLine)); - memset(gbSCXLine, register_SCX, sizeof(gbSCXLine)); - memset(gbBgpLine, (gbBgp[0] | (gbBgp[1]<<2) | (gbBgp[2]<<4) | - (gbBgp[3]<<6)), sizeof(gbBgpLine)); - memset(gbObp0Line, (gbObp0[0] | (gbObp0[1]<<2) | (gbObp0[2]<<4) | - (gbObp0[3]<<6)), sizeof(gbObp0Line)); - memset(gbObp1Line, (gbObp1[0] | (gbObp1[1]<<2) | (gbObp1[2]<<4) | - (gbObp1[3]<<6)), sizeof(gbObp1Line)); - memset(gbSpritesTicks, 0x0, sizeof(gbSpritesTicks)); - - if (inBios) - { - gbMemoryMap[0x00] = &gbMemory[0x0000]; - if (gbHardware & 5) { - memcpy ((uint8_t *)(gbMemory), (uint8_t *)(gbRom), 0x1000); - memcpy ((uint8_t *)(gbMemory), (uint8_t *)(bios), 0x100); - } else if (gbHardware & 2) { - memcpy ((uint8_t *)(gbMemory), (uint8_t *)(bios), 0x900); - memcpy ((uint8_t *)(gbMemory + 0x100), (uint8_t *)(gbRom + 0x100), 0x100); } - } - else - 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]; + if (version < 11) { + gbWriteMemory(0xff00, 0); + gbMemory[0xff04] = register_DIV; + gbMemory[0xff05] = register_TIMA; + gbMemory[0xff06] = register_TMA; + gbMemory[0xff07] = register_TAC; + gbMemory[0xff40] = register_LCDC; + gbMemory[0xff42] = register_SCY; + gbMemory[0xff43] = register_SCX; + gbMemory[0xff44] = register_LY; + gbMemory[0xff45] = register_LYC; + gbMemory[0xff46] = register_DMA; + gbMemory[0xff4a] = register_WY; + gbMemory[0xff4b] = register_WX; + gbMemory[0xff4f] = register_VBK; + gbMemory[0xff51] = register_HDMA1; + gbMemory[0xff52] = register_HDMA2; + gbMemory[0xff53] = register_HDMA3; + gbMemory[0xff54] = register_HDMA4; + gbMemory[0xff55] = register_HDMA5; + gbMemory[0xff70] = register_SVBK; + gbMemory[0xffff] = register_IE; + GBDIV_CLOCK_TICKS = 64; - switch(gbRomType) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - // MBC 1 - memoryUpdateMapMBC1(); - break; - case 0x05: - case 0x06: - // MBC2 - memoryUpdateMapMBC2(); - break; - case 0x0b: - case 0x0c: - case 0x0d: - // MMM01 - memoryUpdateMapMMM01(); - 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 0x56: - // GS3 - memoryUpdateMapGS3(); - break; - case 0xfd: - // TAMA5 - memoryUpdateMapTAMA5(); - break; - case 0xfe: - // HuC3 - memoryUpdateMapHuC3(); - break; - case 0xff: - // HuC1 - memoryUpdateMapHuC1(); - break; - } + if (gbSpeed) + gbDivTicks /= 2; - if(gbCgbMode) { - utilGzRead(gzFile, gbVram, 0x4000); - utilGzRead(gzFile, gbWram, 0x8000); + if ((gbLcdMode == 0) && (register_STAT & 8)) + gbInt48Signal |= 1; + if ((gbLcdMode == 1) && (register_STAT & 0x10)) + gbInt48Signal |= 2; + if ((gbLcdMode == 2) && (register_STAT & 0x20)) + gbInt48Signal |= 4; + if ((register_LY == register_LYC) && (register_STAT & 0x40)) + gbInt48Signal |= 8; - int value = register_SVBK; - if(value == 0) - value = 1; + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS; - gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000]; - gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000]; - gbMemoryMap[0x0d] = &gbWram[value * 0x1000]; - } + if (gbLcdMode == 2) + gbLcdLYIncrementTicks -= GBLCD_MODE_2_CLOCK_TICKS - gbLcdTicks; + else if (gbLcdMode == 3) + gbLcdLYIncrementTicks -= GBLCD_MODE_2_CLOCK_TICKS + GBLCD_MODE_3_CLOCK_TICKS - gbLcdTicks; + else if (gbLcdMode == 0) + gbLcdLYIncrementTicks = gbLcdTicks; + else if (gbLcdMode == 1) { + gbLcdLYIncrementTicks = gbLcdTicks % GBLY_INCREMENT_CLOCK_TICKS; + if (register_LY == 0x99) + gbLcdLYIncrementTicks = gbLine99Ticks; + else if (register_LY == 0) + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; + } - gbSoundReadGame(version, gzFile); - - if (gbCgbMode && gbSgbMode) { - gbSgbMode = 0; - } - - if(gbBorderOn && !gbSgbMask) { - gbSgbRenderBorder(); - } - - systemDrawScreen(); - - if(version > GBSAVE_GAME_VERSION_1) - { - if( skipSaveGameCheats ) { - gbCheatsReadGameSkip(gzFile, version); + gbLcdModeDelayed = gbLcdMode; + gbLcdTicksDelayed = gbLcdTicks--; + gbLcdLYIncrementTicksDelayed = gbLcdLYIncrementTicks--; + gbInterruptWait = 0; + memset(gbSpritesTicks, 0, sizeof(gbSpritesTicks)); } else { - gbCheatsReadGame(gzFile, version); + gbLcdModeDelayed = utilReadInt(gzFile); + gbLcdTicksDelayed = utilReadInt(gzFile); + gbLcdLYIncrementTicksDelayed = utilReadInt(gzFile); + gbSpritesTicks[299] = utilReadInt(gzFile) & 0xff; + gbTimerModeChange = (utilReadInt(gzFile) ? true : false); + gbTimerOnChange = (utilReadInt(gzFile) ? true : false); + gbHardware = utilReadInt(gzFile); + gbBlackScreen = (utilReadInt(gzFile) ? true : false); + oldRegister_WY = utilReadInt(gzFile); + gbWindowLine = utilReadInt(gzFile); + inUseRegister_WY = utilReadInt(gzFile); + gbScreenOn = (utilReadInt(gzFile) ? true : false); } - } - - if (version<11) - { - gbWriteMemory(0xff00, 0); - gbMemory[0xff04] = register_DIV; - gbMemory[0xff05] = register_TIMA; - gbMemory[0xff06] = register_TMA; - gbMemory[0xff07] = register_TAC; - gbMemory[0xff40] = register_LCDC; - gbMemory[0xff42] = register_SCY; - gbMemory[0xff43] = register_SCX; - gbMemory[0xff44] = register_LY; - gbMemory[0xff45] = register_LYC; - gbMemory[0xff46] = register_DMA; - gbMemory[0xff4a] = register_WY; - gbMemory[0xff4b] = register_WX; - gbMemory[0xff4f] = register_VBK; - gbMemory[0xff51] = register_HDMA1; - gbMemory[0xff52] = register_HDMA2; - gbMemory[0xff53] = register_HDMA3; - gbMemory[0xff54] = register_HDMA4; - gbMemory[0xff55] = register_HDMA5; - gbMemory[0xff70] = register_SVBK; - gbMemory[0xffff] = register_IE; - GBDIV_CLOCK_TICKS = 64; if (gbSpeed) - gbDivTicks /=2; + gbLine99Ticks *= 2; - if ((gbLcdMode == 0) && (register_STAT & 8)) - gbInt48Signal |= 1; - if ((gbLcdMode == 1) && (register_STAT & 0x10)) - gbInt48Signal |= 2; - if ((gbLcdMode == 2) && (register_STAT & 0x20)) - gbInt48Signal |= 4; - if ((register_LY==register_LYC) && (register_STAT & 0x40)) - gbInt48Signal |= 8; + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS; + if (version >= 12 && utilReadInt(gzFile) != 0x12345678) + assert(false); // fails if something read too much/little from file - if (gbLcdMode == 2) - gbLcdLYIncrementTicks-=GBLCD_MODE_2_CLOCK_TICKS-gbLcdTicks; - else if (gbLcdMode == 3) - gbLcdLYIncrementTicks -=GBLCD_MODE_2_CLOCK_TICKS+GBLCD_MODE_3_CLOCK_TICKS-gbLcdTicks; - else if (gbLcdMode == 0) - gbLcdLYIncrementTicks =gbLcdTicks; - else if (gbLcdMode == 1) - { - gbLcdLYIncrementTicks = gbLcdTicks % GBLY_INCREMENT_CLOCK_TICKS; - if (register_LY == 0x99) - gbLcdLYIncrementTicks =gbLine99Ticks; - else if (register_LY == 0) - gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; - } - - gbLcdModeDelayed = gbLcdMode; - gbLcdTicksDelayed = gbLcdTicks--; - gbLcdLYIncrementTicksDelayed = gbLcdLYIncrementTicks--; - gbInterruptWait = 0; - memset(gbSpritesTicks,0,sizeof(gbSpritesTicks)); - } - else - { - gbLcdModeDelayed = utilReadInt(gzFile); - gbLcdTicksDelayed = utilReadInt(gzFile); - gbLcdLYIncrementTicksDelayed = utilReadInt(gzFile); - gbSpritesTicks[299] = utilReadInt(gzFile) & 0xff; - gbTimerModeChange = (utilReadInt(gzFile) ? true : false); - gbTimerOnChange = (utilReadInt(gzFile) ? true : false); - gbHardware = utilReadInt(gzFile); - gbBlackScreen = (utilReadInt(gzFile) ? true : false); - oldRegister_WY = utilReadInt(gzFile); - gbWindowLine = utilReadInt(gzFile); - inUseRegister_WY = utilReadInt(gzFile); - gbScreenOn = (utilReadInt(gzFile) ? true : false); - } - - if (gbSpeed) - gbLine99Ticks *= 2; - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - if ( version >= 12 && utilReadInt( gzFile ) != 0x12345678 ) - assert( false ); // fails if something read too much/little from file - - return true; + return true; } -bool gbReadMemSaveState(char *memory, int available) +bool gbReadMemSaveState(char* memory, int available) { - gzFile gzFile = utilMemGzOpen(memory, available, "r"); + gzFile gzFile = utilMemGzOpen(memory, available, "r"); - bool res = gbReadSaveState(gzFile); + bool res = gbReadSaveState(gzFile); - utilGzClose(gzFile); + utilGzClose(gzFile); - return res; + return res; } -bool gbReadSaveState(const char *name) +bool gbReadSaveState(const char* name) { - gzFile gzFile = utilGzOpen(name,"rb"); + gzFile gzFile = utilGzOpen(name, "rb"); - if(gzFile == NULL) { - return false; - } + if (gzFile == NULL) { + return false; + } - bool res = gbReadSaveState(gzFile); + bool res = gbReadSaveState(gzFile); - utilGzClose(gzFile); + utilGzClose(gzFile); - return res; + return res; } -bool gbWritePNGFile(const char *fileName) +bool gbWritePNGFile(const char* fileName) { - if(gbBorderOn) - return utilWritePNGFile(fileName, 256, 224, pix); - return utilWritePNGFile(fileName, 160, 144, pix); + if (gbBorderOn) + return utilWritePNGFile(fileName, 256, 224, pix); + return utilWritePNGFile(fileName, 160, 144, pix); } -bool gbWriteBMPFile(const char *fileName) +bool gbWriteBMPFile(const char* fileName) { - if(gbBorderOn) - return utilWriteBMPFile(fileName, 256, 224, pix); - return utilWriteBMPFile(fileName, 160, 144, pix); + if (gbBorderOn) + return utilWriteBMPFile(fileName, 256, 224, pix); + return utilWriteBMPFile(fileName, 160, 144, pix); } void gbCleanUp() { - if(gbRam != NULL) { - free(gbRam); - gbRam = NULL; - } + if (gbRam != NULL) { + free(gbRam); + gbRam = NULL; + } - if(gbRom != NULL) { - free(gbRom); - gbRom = NULL; - } + if (gbRom != NULL) { + free(gbRom); + gbRom = NULL; + } - if(bios != NULL) { - free(bios); - bios = NULL; - } + if (bios != NULL) { + free(bios); + bios = NULL; + } - if(gbMemory != NULL) { - free(gbMemory); - gbMemory = NULL; - } + if (gbMemory != NULL) { + free(gbMemory); + gbMemory = NULL; + } - if(gbLineBuffer != NULL) { - free(gbLineBuffer); - gbLineBuffer = NULL; - } + if (gbLineBuffer != NULL) { + free(gbLineBuffer); + gbLineBuffer = NULL; + } - if(pix != NULL) { - free(pix); - pix = NULL; - } + if (pix != NULL) { + free(pix); + pix = NULL; + } - gbSgbShutdown(); + gbSgbShutdown(); - if(gbVram != NULL) { - free(gbVram); - gbVram = NULL; - } + if (gbVram != NULL) { + free(gbVram); + gbVram = NULL; + } - if(gbWram != NULL) { - free(gbWram); - gbWram = NULL; - } + if (gbWram != NULL) { + free(gbWram); + gbWram = NULL; + } - if(gbTAMA5ram != NULL) { - free(gbTAMA5ram); - gbTAMA5ram = NULL; - } + if (gbTAMA5ram != NULL) { + free(gbTAMA5ram); + gbTAMA5ram = NULL; + } - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; } -bool gbLoadRom(const char *szFile) +bool gbLoadRom(const char* szFile) { - int size = 0; + int size = 0; - if(gbRom != NULL) { - gbCleanUp(); - } + if (gbRom != NULL) { + gbCleanUp(); + } - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - gbRom = utilLoad(szFile, - utilIsGBImage, - NULL, - size); - if(!gbRom) - return false; + gbRom = utilLoad(szFile, + utilIsGBImage, + NULL, + size); + if (!gbRom) + return false; - gbRomSize = size; + gbRomSize = size; - gbBatteryError = false; + gbBatteryError = false; - if(bios != NULL) { - free(bios); - bios = NULL; - } - bios = (uint8_t *)calloc(1,0x900); + if (bios != NULL) { + free(bios); + bios = NULL; + } + bios = (uint8_t*)calloc(1, 0x900); - return gbUpdateSizes(); + 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]]) { - uint8_t *gbRomNew = (uint8_t *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); - if( !gbRomNew ) { assert( false ); return false; }; - gbRom = gbRomNew; - for (int i = gbRomSize; igbRomSizes[gbRom[0x148]]) && (genericflashcardEnable)) - { - gbRomSize = gbRomSize>>16; - gbRom[0x148] = 0; - if (gbRomSize) - { - while (!((gbRomSize & 1) || (gbRom[0x148] == 7))) - { - gbRom[0x148]++; - gbRomSize>>=1; - } - gbRom[0x148]++; + if (gbRom[0x148] > 8) { + systemMessage(MSG_UNSUPPORTED_ROM_SIZE, + N_("Unsupported rom size %02x"), gbRom[0x148]); + return false; } - uint8_t *gbRomNew = (uint8_t *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); - if( !gbRomNew ) { assert( false ); return false; }; - gbRom = gbRomNew; - } - gbRomSize = gbRomSizes[gbRom[0x148]]; - gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; + if (gbRomSize < gbRomSizes[gbRom[0x148]]) { + uint8_t* gbRomNew = (uint8_t*)realloc(gbRom, gbRomSizes[gbRom[0x148]]); + if (!gbRomNew) { + assert(false); + return false; + }; + gbRom = gbRomNew; + for (int i = gbRomSize; i < gbRomSizes[gbRom[0x148]]; i++) + gbRom[i] = 0x00; // Not sure if it's 0x00, 0xff or random data... + } + // (it's in the case a cart is 'lying' on its size. + else if ((gbRomSize > gbRomSizes[gbRom[0x148]]) && (genericflashcardEnable)) { + gbRomSize = gbRomSize >> 16; + gbRom[0x148] = 0; + if (gbRomSize) { + while (!((gbRomSize & 1) || (gbRom[0x148] == 7))) { + gbRom[0x148]++; + gbRomSize >>= 1; + } + gbRom[0x148]++; + } + uint8_t* gbRomNew = (uint8_t*)realloc(gbRom, gbRomSizes[gbRom[0x148]]); + if (!gbRomNew) { + assert(false); + return false; + }; + gbRom = gbRomNew; + } + gbRomSize = gbRomSizes[gbRom[0x148]]; + gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; - // The 'genericflashcard' option allows some PD to work. - // However, the setting is dangerous (if you let in enabled - // and play a normal game, it might just break everything). - // That's why it is not saved in the emulator options. - // Also I added some checks in VBA to make sure your saves will not be - // overwritten if you wrongly enable this option for a game - // you already played (and vice-versa, ie. if you forgot to - // enable the option for a game you played with it enabled, like Shawu Story). - uint8_t ramsize = genericflashcardEnable ? 5 : gbRom[0x149]; - gbRom[0x149] = ramsize; + // The 'genericflashcard' option allows some PD to work. + // However, the setting is dangerous (if you let in enabled + // and play a normal game, it might just break everything). + // That's why it is not saved in the emulator options. + // Also I added some checks in VBA to make sure your saves will not be + // overwritten if you wrongly enable this option for a game + // you already played (and vice-versa, ie. if you forgot to + // enable the option for a game you played with it enabled, like Shawu Story). + uint8_t ramsize = genericflashcardEnable ? 5 : gbRom[0x149]; + gbRom[0x149] = ramsize; - if ((gbRom[2] == 0x6D) && (gbRom[5] == 0x47) && (gbRom[6] == 0x65) && (gbRom[7] == 0x6E) && - (gbRom[8] == 0x69) && (gbRom[9] == 0x65) && (gbRom[0xA] == 0x28) && (gbRom[0xB] == 0x54)) - { - gbCheatingDevice = 1; // GameGenie - for (int i = 0; i < 0x20; i++) // Cleans GG hardware registers - gbRom[0x4000+i] = 0; - } - else if (((gbRom[0x104] == 0x44) && (gbRom[0x156] == 0xEA) && (gbRom[0x158] == 0x7F) && - (gbRom[0x159] == 0xEA) && (gbRom[0x15B] == 0x7F)) || ((gbRom[0x165] == 0x3E) && - (gbRom[0x166] == 0xD9) && (gbRom[0x16D] == 0xE1) && (gbRom[0x16E] == 0x7F))) - gbCheatingDevice = 2; // GameShark - else gbCheatingDevice = 0; + if ((gbRom[2] == 0x6D) && (gbRom[5] == 0x47) && (gbRom[6] == 0x65) && (gbRom[7] == 0x6E) && (gbRom[8] == 0x69) && (gbRom[9] == 0x65) && (gbRom[0xA] == 0x28) && (gbRom[0xB] == 0x54)) { + gbCheatingDevice = 1; // GameGenie + for (int i = 0; i < 0x20; i++) // Cleans GG hardware registers + gbRom[0x4000 + i] = 0; + } else if (((gbRom[0x104] == 0x44) && (gbRom[0x156] == 0xEA) && (gbRom[0x158] == 0x7F) && (gbRom[0x159] == 0xEA) && (gbRom[0x15B] == 0x7F)) || ((gbRom[0x165] == 0x3E) && (gbRom[0x166] == 0xD9) && (gbRom[0x16D] == 0xE1) && (gbRom[0x16E] == 0x7F))) + gbCheatingDevice = 2; // GameShark + else + gbCheatingDevice = 0; - if(ramsize > 5) { - systemMessage(MSG_UNSUPPORTED_RAM_SIZE, - N_("Unsupported ram size %02x"), gbRom[0x149]); - return false; - } + if (ramsize > 5) { + systemMessage(MSG_UNSUPPORTED_RAM_SIZE, + N_("Unsupported ram size %02x"), gbRom[0x149]); + return false; + } - gbRamSize = gbRamSizes[ramsize]; - gbRamSizeMask = gbRamSizesMasks[ramsize]; + gbRamSize = gbRamSizes[ramsize]; + gbRamSizeMask = gbRamSizesMasks[ramsize]; - gbRomType = gbRom[0x147]; - if (genericflashcardEnable) - { - /*if (gbRomType<2) + gbRomType = gbRom[0x147]; + if (genericflashcardEnable) { + /*if (gbRomType<2) gbRomType =3; else if ((gbRomType == 0xc) || (gbRomType == 0xf) || (gbRomType == 0x12) || (gbRomType == 0x16) || (gbRomType == 0x1a) || (gbRomType == 0x1d)) @@ -4540,332 +4266,319 @@ bool gbUpdateSizes() gbRomType+=2; else if ((gbRomType == 0x5) || (gbRomType == 0x6)) gbRomType = 0x1a;*/ - gbRomType = 0x1b; - } - else if (gbCheatingDevice == 1) - gbRomType = 0x55; - else if (gbCheatingDevice == 2) - gbRomType = 0x56; + gbRomType = 0x1b; + } else if (gbCheatingDevice == 1) + gbRomType = 0x55; + else if (gbCheatingDevice == 2) + gbRomType = 0x56; - gbRom[0x147] = gbRomType; + gbRom[0x147] = gbRomType; - mapperReadRAM = NULL; + mapperReadRAM = NULL; - switch(gbRomType) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x08: - case 0x09: - // MBC 1 - mapper = mapperMBC1ROM; - mapperRAM = mapperMBC1RAM; - mapperReadRAM = mapperMBC1ReadRAM; - break; - case 0x05: - case 0x06: - // MBC2 - mapper = mapperMBC2ROM; - mapperRAM = mapperMBC2RAM; - gbRamSize = 0x200; - gbRamSizeMask = 0x1ff; - break; - case 0x0b: - case 0x0c: - case 0x0d: - // MMM01 - mapper = mapperMMM01ROM; - mapperRAM = mapperMMM01RAM; - break; - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0xfc: - // MBC 3 - mapper = mapperMBC3ROM; - mapperRAM = mapperMBC3RAM; - mapperReadRAM = mapperMBC3ReadRAM; - break; - case 0x19: - case 0x1a: - case 0x1b: - // MBC5 - mapper = mapperMBC5ROM; - mapperRAM = mapperMBC5RAM; - mapperReadRAM = mapperMBC5ReadRAM; - break; - case 0x1c: - case 0x1d: - case 0x1e: - // MBC 5 Rumble - mapper = mapperMBC5ROM; - mapperRAM = mapperMBC5RAM; - mapperReadRAM = mapperMBC5ReadRAM; - break; - case 0x22: - // MBC 7 - mapper = mapperMBC7ROM; - mapperRAM = mapperMBC7RAM; - mapperReadRAM = mapperMBC7ReadRAM; - gbRamSize = 0x200; - gbRamSizeMask = 0x1ff; - break; + switch (gbRomType) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + // MBC 1 + mapper = mapperMBC1ROM; + mapperRAM = mapperMBC1RAM; + mapperReadRAM = mapperMBC1ReadRAM; + break; + case 0x05: + case 0x06: + // MBC2 + mapper = mapperMBC2ROM; + mapperRAM = mapperMBC2RAM; + gbRamSize = 0x200; + gbRamSizeMask = 0x1ff; + break; + case 0x0b: + case 0x0c: + case 0x0d: + // MMM01 + mapper = mapperMMM01ROM; + mapperRAM = mapperMMM01RAM; + break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0xfc: + // MBC 3 + mapper = mapperMBC3ROM; + mapperRAM = mapperMBC3RAM; + mapperReadRAM = mapperMBC3ReadRAM; + break; + case 0x19: + case 0x1a: + case 0x1b: + // MBC5 + mapper = mapperMBC5ROM; + mapperRAM = mapperMBC5RAM; + mapperReadRAM = mapperMBC5ReadRAM; + break; + case 0x1c: + case 0x1d: + case 0x1e: + // MBC 5 Rumble + mapper = mapperMBC5ROM; + mapperRAM = mapperMBC5RAM; + mapperReadRAM = mapperMBC5ReadRAM; + break; + case 0x22: + // MBC 7 + mapper = mapperMBC7ROM; + mapperRAM = mapperMBC7RAM; + mapperReadRAM = mapperMBC7ReadRAM; + gbRamSize = 0x200; + gbRamSizeMask = 0x1ff; + break; // GG (GameGenie) - case 0x55: - mapper = mapperGGROM; - break; - case 0x56: - // GS (GameShark) - mapper = mapperGS3ROM; - break; - case 0xfd: - // TAMA5 - if (gbRam!= NULL) - { - free(gbRam); - gbRam = NULL; + case 0x55: + mapper = mapperGGROM; + break; + case 0x56: + // GS (GameShark) + mapper = mapperGS3ROM; + break; + case 0xfd: + // TAMA5 + if (gbRam != NULL) { + free(gbRam); + gbRam = NULL; + } + + ramsize = 3; + gbRamSize = gbRamSizes[3]; + gbRamSizeMask = gbRamSizesMasks[3]; + gbRamFill = 0x0; + + gbTAMA5ramSize = 0x100; + + if (gbTAMA5ram == NULL) + gbTAMA5ram = (uint8_t*)malloc(gbTAMA5ramSize); + memset(gbTAMA5ram, 0x0, gbTAMA5ramSize); + + mapperRAM = mapperTAMA5RAM; + mapperReadRAM = mapperTAMA5ReadRAM; + mapperUpdateClock = memoryUpdateTAMA5Clock; + 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"), gbRomType); + return false; } - ramsize = 3; - gbRamSize = gbRamSizes[3]; - gbRamSizeMask = gbRamSizesMasks[3]; - gbRamFill = 0x0; + if (gbRamSize) { + gbRam = (uint8_t*)malloc(gbRamSize); + memset(gbRam, gbRamFill, gbRamSize); + } - gbTAMA5ramSize = 0x100; + switch (gbRomType) { + case 0x03: + case 0x06: + case 0x0f: + case 0x10: + case 0x13: + case 0x1b: + case 0x1d: + case 0x1e: + case 0x22: + case 0xfd: + case 0xff: + gbBattery = 1; + break; + } - if (gbTAMA5ram == NULL) - gbTAMA5ram = (uint8_t *)malloc(gbTAMA5ramSize); - memset(gbTAMA5ram, 0x0, gbTAMA5ramSize); + gbInit(); - mapperRAM = mapperTAMA5RAM; - mapperReadRAM = mapperTAMA5ReadRAM; - mapperUpdateClock = memoryUpdateTAMA5Clock; - 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"), gbRomType); - return false; - } + //gbReset(); - if(gbRamSize) { - gbRam = (uint8_t *)malloc(gbRamSize); - memset(gbRam, gbRamFill, gbRamSize); - } + switch (gbRomType) { + case 0x1c: + case 0x1d: + case 0x1e: + gbDataMBC5.isRumbleCartridge = 1; + } - switch(gbRomType) { - case 0x03: - case 0x06: - case 0x0f: - case 0x10: - case 0x13: - case 0x1b: - case 0x1d: - case 0x1e: - case 0x22: - case 0xfd: - case 0xff: - gbBattery = 1; - break; - } - - gbInit(); - - //gbReset(); - - switch(gbRomType) { - case 0x1c: - case 0x1d: - case 0x1e: - gbDataMBC5.isRumbleCartridge = 1; - } - - return true; + return true; } -int gbGetNextEvent (int _clockTicks) +int gbGetNextEvent(int _clockTicks) { - if (register_LCDC & 0x80) - { - if(gbLcdTicks < _clockTicks) - _clockTicks = gbLcdTicks; + if (register_LCDC & 0x80) { + if (gbLcdTicks < _clockTicks) + _clockTicks = gbLcdTicks; - if(gbLcdTicksDelayed < _clockTicks) - _clockTicks = gbLcdTicksDelayed; + if (gbLcdTicksDelayed < _clockTicks) + _clockTicks = gbLcdTicksDelayed; - if(gbLcdLYIncrementTicksDelayed < _clockTicks) - _clockTicks = gbLcdLYIncrementTicksDelayed; - } + if (gbLcdLYIncrementTicksDelayed < _clockTicks) + _clockTicks = gbLcdLYIncrementTicksDelayed; + } - if(gbLcdLYIncrementTicks < _clockTicks) - _clockTicks = gbLcdLYIncrementTicks; + if (gbLcdLYIncrementTicks < _clockTicks) + _clockTicks = gbLcdLYIncrementTicks; - if(gbSerialOn && (gbSerialTicks < _clockTicks)) - _clockTicks = gbSerialTicks; + if (gbSerialOn && (gbSerialTicks < _clockTicks)) + _clockTicks = gbSerialTicks; - if(gbTimerOn && (((gbInternalTimer) & gbTimerMask[gbTimerMode])+1 < _clockTicks)) - _clockTicks = ((gbInternalTimer) & gbTimerMask[gbTimerMode])+1; + if (gbTimerOn && (((gbInternalTimer)&gbTimerMask[gbTimerMode]) + 1 < _clockTicks)) + _clockTicks = ((gbInternalTimer)&gbTimerMask[gbTimerMode]) + 1; - //if(soundTicks && (soundTicks < _clockTicks)) - // _clockTicks = soundTicks; + //if(soundTicks && (soundTicks < _clockTicks)) + // _clockTicks = soundTicks; - if ((_clockTicks<=0) || (gbInterruptWait)) - _clockTicks = 1; + if ((_clockTicks <= 0) || (gbInterruptWait)) + _clockTicks = 1; - return _clockTicks; + return _clockTicks; } void gbDrawLine() { - switch(systemColorDepth) { - case 16: - { - uint16_t * dest = (uint16_t *)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++]]; + switch (systemColorDepth) { + case 16: { + uint16_t* dest = (uint16_t*)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++]]; + *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++ = 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: { + uint8_t* dest = (uint8_t*)pix + 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + gbBorderColumnSkip); + for (int x = 0; x < 160;) { + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + } + } break; + + case 32: { + uint32_t* dest = (uint32_t*)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; } - break; - - case 24: - { - uint8_t *dest = (uint8_t *)pix + - 3*(gbBorderLineSkip * (register_LY + gbBorderRowSkip) + - gbBorderColumnSkip); - for(int x = 0; x < 160;) { - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - *((uint32_t *)dest) = systemColorMap32[gbLineMix[x++]]; - dest+= 3; - } - } - break; - - case 32: - { - uint32_t * dest = (uint32_t *)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; - } } void gbEmulate(int ticksToStop) { - gbRegister tempRegister; - uint8_t tempValue; - int8_t offset; + gbRegister tempRegister; + uint8_t tempValue; + int8_t offset; - clockTicks = 0; - gbDmaTicks = 0; + clockTicks = 0; + gbDmaTicks = 0; - register int opcode = 0; + register int opcode = 0; - int opcode1 = 0; - int opcode2 = 0; - bool execute = false; + int opcode1 = 0; + int opcode2 = 0; + bool execute = false; - while(1) { - uint16_t oldPCW = PC.W; + while (1) { + uint16_t oldPCW = PC.W; - if(IFF & 0x80) { - if(register_LCDC & 0x80) { - clockTicks = gbLcdTicks; - } else - clockTicks = 1000; + if (IFF & 0x80) { + if (register_LCDC & 0x80) { + clockTicks = gbLcdTicks; + } else + clockTicks = 1000; - clockTicks = gbGetNextEvent(clockTicks); + clockTicks = gbGetNextEvent(clockTicks); - /*if(gbLcdTicksDelayed < clockTicks) + /*if(gbLcdTicksDelayed < clockTicks) clockTicks = gbLcdTicksDelayed; if(gbLcdLYIncrementTicksDelayed < clockTicks) @@ -4886,966 +4599,854 @@ void gbEmulate(int ticksToStop) if ((clockTicks<=0) || (gbInterruptWait)) clockTicks = 1;*/ - } else { + } else { - // First we apply the clockTicks, then we execute the opcodes. - opcode1 = 0; - opcode2 = 0; - execute = true; + // First we apply the clockTicks, then we execute the opcodes. + opcode1 = 0; + opcode2 = 0; + execute = true; - opcode2 = opcode1 = opcode = gbReadOpcode(PC.W++); + opcode2 = opcode1 = opcode = gbReadOpcode(PC.W++); - // If HALT state was launched while IME = 0 and (register_IF & register_IE & 0x1F), - // PC.W is not incremented for the first byte of the next instruction. - if (IFF & 2) - { - PC.W--; - IFF &= ~2; - } + // If HALT state was launched while IME = 0 and (register_IF & register_IE & 0x1F), + // PC.W is not incremented for the first byte of the next instruction. + if (IFF & 2) { + PC.W--; + IFF &= ~2; + } - clockTicks = gbCycles[opcode]; + clockTicks = gbCycles[opcode]; - switch(opcode) { - case 0xCB: - // extended opcode - opcode2 = opcode = gbReadOpcode(PC.W++); - clockTicks = gbCyclesCB[opcode]; - break; - } - gbOldClockTicks = clockTicks-1; - gbIntBreak = 1; - } + switch (opcode) { + case 0xCB: + // extended opcode + opcode2 = opcode = gbReadOpcode(PC.W++); + clockTicks = gbCyclesCB[opcode]; + break; + } + gbOldClockTicks = clockTicks - 1; + gbIntBreak = 1; + } + if (!emulating) + return; - if(!emulating) - return; + // For 'breakpoint' support (opcode 0xFC is considered as a breakpoint) + if ((clockTicks == 0) && execute) { + PC.W = oldPCW; + return; + } - // For 'breakpoint' support (opcode 0xFC is considered as a breakpoint) - if ((clockTicks==0) && execute) - { - PC.W = oldPCW; - return; - } - - - if (!(IFF & 0x80)) - clockTicks = 1; + if (!(IFF & 0x80)) + clockTicks = 1; gbRedoLoop: - - - if (gbInterruptWait) - gbInterruptWait = 0; - else - gbInterruptLaunched = 0; - - - // Used for the EI/DI instruction's delay. - if (IFF & 0x38) - { - int tempIFF = (IFF >> 4) & 3; - - if (tempIFF <=clockTicks) - { - tempIFF = 0; - IFF |=1; - } + if (gbInterruptWait) + gbInterruptWait = 0; else - tempIFF -= clockTicks; - IFF = (IFF & 0xCF) | (tempIFF <<4); + gbInterruptLaunched = 0; - if (IFF & 0x08) - IFF &= 0x82; - } + // Used for the EI/DI instruction's delay. + if (IFF & 0x38) { + int tempIFF = (IFF >> 4) & 3; + if (tempIFF <= clockTicks) { + tempIFF = 0; + IFF |= 1; + } else + tempIFF -= clockTicks; + IFF = (IFF & 0xCF) | (tempIFF << 4); - if (register_LCDCBusy) - { - register_LCDCBusy-=clockTicks; - if (register_LCDCBusy<0) - register_LCDCBusy = 0; - } + if (IFF & 0x08) + IFF &= 0x82; + } + if (register_LCDCBusy) { + register_LCDCBusy -= clockTicks; + if (register_LCDCBusy < 0) + register_LCDCBusy = 0; + } - if(gbSgbMode) { - if(gbSgbPacketTimeout) { - gbSgbPacketTimeout -= clockTicks; + if (gbSgbMode) { + if (gbSgbPacketTimeout) { + gbSgbPacketTimeout -= clockTicks; - if(gbSgbPacketTimeout <= 0) - gbSgbResetPacketState(); - } - } + if (gbSgbPacketTimeout <= 0) + gbSgbResetPacketState(); + } + } - ticksToStop -= clockTicks; + ticksToStop -= clockTicks; - // DIV register emulation - gbDivTicks -= clockTicks; - while(gbDivTicks <= 0) { - gbMemory[0xff04] = ++register_DIV; - gbDivTicks += GBDIV_CLOCK_TICKS; - } + // DIV register emulation + gbDivTicks -= clockTicks; + while (gbDivTicks <= 0) { + gbMemory[0xff04] = ++register_DIV; + gbDivTicks += GBDIV_CLOCK_TICKS; + } - if(register_LCDC & 0x80) { - // LCD stuff + if (register_LCDC & 0x80) { + // LCD stuff - gbLcdTicks -= clockTicks; - gbLcdTicksDelayed -= clockTicks; - gbLcdLYIncrementTicks -= clockTicks; - gbLcdLYIncrementTicksDelayed -= clockTicks; + gbLcdTicks -= clockTicks; + gbLcdTicksDelayed -= clockTicks; + gbLcdLYIncrementTicks -= clockTicks; + gbLcdLYIncrementTicksDelayed -= clockTicks; + // our counters are off, see what we need to do - // our counters are off, see what we need to do + // This looks (and kinda is) complicated, however this + // is the only way I found to emulate properly the way + // the real hardware operates... + while (((gbLcdTicks <= 0) && (gbLCDChangeHappened == false)) || ((gbLcdTicksDelayed <= 0) && (gbLCDChangeHappened == true)) || ((gbLcdLYIncrementTicks <= 0) && (gbLYChangeHappened == false)) || ((gbLcdLYIncrementTicksDelayed <= 0) && (gbLYChangeHappened == true))) { - // This looks (and kinda is) complicated, however this - // is the only way I found to emulate properly the way - // the real hardware operates... - while(((gbLcdTicks <= 0) && (gbLCDChangeHappened == false)) || - ((gbLcdTicksDelayed <= 0) && (gbLCDChangeHappened == true)) || - ((gbLcdLYIncrementTicks <= 0) && (gbLYChangeHappened == false)) || - ((gbLcdLYIncrementTicksDelayed<=0) && (gbLYChangeHappened == true))) - { + if ((gbLcdLYIncrementTicks <= 0) && (!gbLYChangeHappened)) { + gbLYChangeHappened = true; + gbMemory[0xff44] = register_LY = (register_LY + 1) % 154; - if ((gbLcdLYIncrementTicks <= 0) && (!gbLYChangeHappened)) - { - gbLYChangeHappened = true; - gbMemory[0xff44] = register_LY = (register_LY + 1) % 154; - - if (register_LY == 0x91) - { - /* if (IFF & 0x80) + if (register_LY == 0x91) { + /* if (IFF & 0x80) gbScreenOn = !gbScreenOn; else*/ if (register_LCDC & 0x80) - gbScreenOn = true; - } - - gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; - - if (gbLcdMode == 1) - { - - if(register_LY == 153) - gbLcdLYIncrementTicks -= GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; - else if(register_LY == 0) - gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; - } - - // GB only 'bug' : Halt state is broken one tick before LY==LYC interrupt - // is reflected in the registers. - if ((gbHardware & 5) && (IFF & 0x80) && (register_LY == register_LYC) - && (register_STAT & 0x40) && (register_LY != 0)) - { - if (!((gbLcdModeDelayed != 1) && (register_LY==0))) - { - gbInt48Signal &= ~9; - gbCompareLYToLYC(); - gbLYChangeHappened = false; - gbMemory[0xff41] = register_STAT; - gbMemory[0xff0f] = register_IF; - } - - gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks+1; - } - } - - - if ((gbLcdTicks <= 0) && (!gbLCDChangeHappened)) - { - gbLCDChangeHappened = true; - - switch(gbLcdMode) - { - case 0: - { - // H-Blank - // check if we reached the V-Blank period - if(register_LY == 144) { - // Yes, V-Blank - // set the LY increment counter - if (gbHardware & 0x5) - { - register_IF |= 1; // V-Blank interrupt - } - - gbInt48Signal &= ~6; - if(register_STAT & 0x10) - { - // send LCD interrupt only if no interrupt 48h signal... - if ((!(gbInt48Signal & 1)) && ((!(gbInt48Signal & 8)) || (gbHardware & 0x0a))) - { - register_IF |=2; - gbInterruptLaunched |= 2; - if (gbHardware & 0xa) - gbInterruptWait = 1; - } - gbInt48Signal |= 2; - } - gbInt48Signal &= ~1; - - gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; - gbLcdMode = 1; - - } else { - // go the the OAM being accessed mode - gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; - gbLcdMode = 2; - - gbInt48Signal &= ~6; - if(register_STAT & 0x20) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!gbInt48Signal) - { - register_IF |= 2; - gbInterruptLaunched |= 2; - } - gbInt48Signal |= 4; - } - gbInt48Signal &= ~1; - } - } - break; - case 1: - { - // V-Blank - // next mode is OAM being accessed mode - gbInt48Signal &= ~5; - if(register_STAT & 0x20) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!gbInt48Signal) - { - register_IF |= 2; - gbInterruptLaunched |= 2; - if ((gbHardware & 0xa) && (IFF & 0x80)) - gbInterruptWait = 1; - } - gbInt48Signal |= 4; - } - gbInt48Signal &= ~2; - - gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; - - gbLcdMode = 2; - register_LY = 0x00; - - } - break; - case 2: - { - - // OAM being accessed mode - // next mode is OAM and VRAM in use - if ((gbScreenOn) && (register_LCDC & 0x80)) - { - gbDrawSprites(false); - // Used to add a one tick delay when a window line is drawn. - //(fixes a part of Carmaggedon problem) - if((register_LCDC & 0x01 || gbCgbMode) && (register_LCDC & 0x20) && - (gbWindowLine != -2)) { - - int inUseRegister_WY = 0; - int tempgbWindowLine = gbWindowLine; - - if ((tempgbWindowLine == -1) || (tempgbWindowLine>144)) - { - inUseRegister_WY = oldRegister_WY; - if (register_LY>oldRegister_WY) - tempgbWindowLine = 146; - } - - if(register_LY >= inUseRegister_WY) { - - if (tempgbWindowLine == -1) - tempgbWindowLine = 0; - - int wx = register_WX; - wx -= 7; - if (wx<0) - wx = 0; - - if((wx <= 159) && (tempgbWindowLine <= 143)) - { - for (int i = wx; i<300; i++) - if (gbSpeed) - gbSpritesTicks[i]+=3; - else - gbSpritesTicks[i]+=1; - } - } - } - } - - gbInt48Signal &= ~7; - - gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS+gbSpritesTicks[299]; - gbLcdMode = 3; - } - break; - case 3: - { - // OAM and VRAM in use - // next mode is H-Blank - - - gbInt48Signal &= ~7; - if(register_STAT & 0x08) - { - // send LCD interrupt only if no interrupt 48h signal... - if (!(gbInt48Signal & 8)) - { - register_IF |= 2; - if ((gbHardware & 0xa) && (IFF & 0x80)) - gbInterruptWait = 1; - } - gbInt48Signal |= 1; - } - - gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]; - - gbLcdMode = 0; - - // No HDMA during HALT ! - if(gbHdmaOn && (!(IFF & 0x80) || (register_IE & register_IF & 0x1f))) { - gbDoHdma(); - } - - } - break; - } - } - - - if ((gbLcdTicksDelayed <= 0) && (gbLCDChangeHappened)) { - int framesToSkip = systemFrameSkip; - if(speedup) - framesToSkip = 9; // try 6 FPS during speedup - //gbLcdTicksDelayed = gbLcdTicks+1; - gbLCDChangeHappened = false; - switch(gbLcdModeDelayed) { - case 0: - { - // H-Blank - - memset(gbSCYLine,gbSCYLine[299],sizeof(gbSCYLine)); - memset(gbSCXLine,gbSCXLine[299],sizeof(gbSCXLine)); - memset(gbBgpLine,gbBgpLine[299],sizeof(gbBgpLine)); - memset(gbObp0Line,gbObp0Line[299],sizeof(gbObp0Line)); - memset(gbObp1Line,gbObp1Line[299],sizeof(gbObp1Line)); - memset(gbSpritesTicks,gbSpritesTicks[299],sizeof(gbSpritesTicks)); - - if (gbWindowLine <0) - oldRegister_WY = register_WY; - // check if we reached the V-Blank period - if(register_LY == 144) { - // Yes, V-Blank - // set the LY increment counter - - if(register_LCDC & 0x80) { - if (gbHardware & 0xa) - { - - register_IF |= 1; // V-Blank interrupt - gbInterruptLaunched |=1; + gbScreenOn = true; } + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; - } + if (gbLcdMode == 1) { - gbLcdTicksDelayed += GBLCD_MODE_1_CLOCK_TICKS; - gbLcdModeDelayed = 1; - - gbFrameCount++; - systemFrame(); - - if((gbFrameCount % 10) == 0) - system10Frames(60); - - if(gbFrameCount >= 60) { - uint32_t currentTime = systemGetClock(); - if(currentTime != gbLastTime) - systemShowSpeed(100000/(currentTime - gbLastTime)); - else - systemShowSpeed(0); - gbLastTime = currentTime; - gbFrameCount = 0; - } - - if(systemReadJoypads()) { - // read joystick - if(gbSgbMode && gbSgbMultiplayer) { - if(gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); + if (register_LY == 153) + gbLcdLYIncrementTicks -= GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; + else if (register_LY == 0) + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } - } - int newmask = gbJoymask[0] & 255; - if(gbRomType == 0x22) { - systemUpdateMotionSensor(); - } + // GB only 'bug' : Halt state is broken one tick before LY==LYC interrupt + // is reflected in the registers. + if ((gbHardware & 5) && (IFF & 0x80) && (register_LY == register_LYC) + && (register_STAT & 0x40) && (register_LY != 0)) { + if (!((gbLcdModeDelayed != 1) && (register_LY == 0))) { + gbInt48Signal &= ~9; + gbCompareLYToLYC(); + gbLYChangeHappened = false; + gbMemory[0xff41] = register_STAT; + gbMemory[0xff0f] = register_IF; + } - if(newmask) - { - gbMemory[0xff0f] = register_IF |= 16; - } - - - newmask = (gbJoymask[0] >> 10); - - speedup = (newmask & 1) ? true : false; - gbCapture = (newmask & 2) ? true : false; - - if(gbCapture && !gbCapturePrevious) { - gbCaptureNumber++; - systemScreenCapture(gbCaptureNumber); - } - gbCapturePrevious = gbCapture; - - if(gbFrameSkipCount >= framesToSkip) { - - if(!gbSgbMask) - { - if (gbBorderOn) - gbSgbRenderBorder(); - //if (gbScreenOn) - systemDrawScreen(); - if(systemPauseOnFrame()) - ticksToStop = 0; - } - gbFrameSkipCount = 0; - } else - gbFrameSkipCount++; - - } else { - // go the the OAM being accessed mode - gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; - gbLcdModeDelayed = 2; - gbInt48Signal &= ~3; - } - } - break; - case 1: - { - // V-Blank - // next mode is OAM being accessed mode - - // gbScreenOn = true; - - oldRegister_WY = register_WY; - - gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; - gbLcdModeDelayed = 2; - - // reset the window line - gbWindowLine = -1; - } - break; - case 2: - { - // OAM being accessed mode - // next mode is OAM and VRAM in use - gbLcdTicksDelayed += GBLCD_MODE_3_CLOCK_TICKS+gbSpritesTicks[299]; - gbLcdModeDelayed = 3; - } - break; - case 3: - { - - // OAM and VRAM in use - // next mode is H-Blank - if((register_LY < 144) && (register_LCDC & 0x80) && gbScreenOn) { - if(!gbSgbMask) { - if(gbFrameSkipCount >= framesToSkip) { - if (!gbBlackScreen) - { - gbRenderLine(); - gbDrawSprites(true); + gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks + 1; } - else if (gbBlackScreen) - { - uint16_t color = gbColorOption ? gbColorFilter[0] : 0; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[3] & 0x7FFF] : gbPalette[3] & 0x7FFF; - for(int i = 0; i < 160; i++) - { - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } + } + + if ((gbLcdTicks <= 0) && (!gbLCDChangeHappened)) { + gbLCDChangeHappened = true; + + switch (gbLcdMode) { + case 0: { + // H-Blank + // check if we reached the V-Blank period + if (register_LY == 144) { + // Yes, V-Blank + // set the LY increment counter + if (gbHardware & 0x5) { + register_IF |= 1; // V-Blank interrupt + } + + gbInt48Signal &= ~6; + if (register_STAT & 0x10) { + // send LCD interrupt only if no interrupt 48h signal... + if ((!(gbInt48Signal & 1)) && ((!(gbInt48Signal & 8)) || (gbHardware & 0x0a))) { + register_IF |= 2; + gbInterruptLaunched |= 2; + if (gbHardware & 0xa) + gbInterruptWait = 1; + } + gbInt48Signal |= 2; + } + gbInt48Signal &= ~1; + + gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; + gbLcdMode = 1; + + } else { + // go the the OAM being accessed mode + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdMode = 2; + + gbInt48Signal &= ~6; + if (register_STAT & 0x20) { + // send LCD interrupt only if no interrupt 48h signal... + if (!gbInt48Signal) { + register_IF |= 2; + gbInterruptLaunched |= 2; + } + gbInt48Signal |= 4; + } + gbInt48Signal &= ~1; + } + } break; + case 1: { + // V-Blank + // next mode is OAM being accessed mode + gbInt48Signal &= ~5; + if (register_STAT & 0x20) { + // send LCD interrupt only if no interrupt 48h signal... + if (!gbInt48Signal) { + register_IF |= 2; + gbInterruptLaunched |= 2; + if ((gbHardware & 0xa) && (IFF & 0x80)) + gbInterruptWait = 1; + } + gbInt48Signal |= 4; + } + gbInt48Signal &= ~2; + + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; + + gbLcdMode = 2; + register_LY = 0x00; + + } break; + case 2: { + + // OAM being accessed mode + // next mode is OAM and VRAM in use + if ((gbScreenOn) && (register_LCDC & 0x80)) { + gbDrawSprites(false); + // Used to add a one tick delay when a window line is drawn. + //(fixes a part of Carmaggedon problem) + if ((register_LCDC & 0x01 || gbCgbMode) && (register_LCDC & 0x20) && (gbWindowLine != -2)) { + + int inUseRegister_WY = 0; + int tempgbWindowLine = gbWindowLine; + + if ((tempgbWindowLine == -1) || (tempgbWindowLine > 144)) { + inUseRegister_WY = oldRegister_WY; + if (register_LY > oldRegister_WY) + tempgbWindowLine = 146; + } + + if (register_LY >= inUseRegister_WY) { + + if (tempgbWindowLine == -1) + tempgbWindowLine = 0; + + int wx = register_WX; + wx -= 7; + if (wx < 0) + wx = 0; + + if ((wx <= 159) && (tempgbWindowLine <= 143)) { + for (int i = wx; i < 300; i++) + if (gbSpeed) + gbSpritesTicks[i] += 3; + else + gbSpritesTicks[i] += 1; + } + } + } + } + + gbInt48Signal &= ~7; + + gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS + gbSpritesTicks[299]; + gbLcdMode = 3; + } break; + case 3: { + // OAM and VRAM in use + // next mode is H-Blank + + gbInt48Signal &= ~7; + if (register_STAT & 0x08) { + // send LCD interrupt only if no interrupt 48h signal... + if (!(gbInt48Signal & 8)) { + register_IF |= 2; + if ((gbHardware & 0xa) && (IFF & 0x80)) + gbInterruptWait = 1; + } + gbInt48Signal |= 1; + } + + gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299]; + + gbLcdMode = 0; + + // No HDMA during HALT ! + if (gbHdmaOn && (!(IFF & 0x80) || (register_IE & register_IF & 0x1f))) { + gbDoHdma(); + } + + } break; } - gbDrawLine(); - } } - } - gbLcdTicksDelayed += GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]; - gbLcdModeDelayed = 0; - } - break; - } - } - if ((gbLcdLYIncrementTicksDelayed <= 0) && (gbLYChangeHappened == true)) - { + if ((gbLcdTicksDelayed <= 0) && (gbLCDChangeHappened)) { + int framesToSkip = systemFrameSkip; + if (speedup) + framesToSkip = 9; // try 6 FPS during speedup + //gbLcdTicksDelayed = gbLcdTicks+1; + gbLCDChangeHappened = false; + switch (gbLcdModeDelayed) { + case 0: { + // H-Blank - gbLYChangeHappened = false; + memset(gbSCYLine, gbSCYLine[299], sizeof(gbSCYLine)); + memset(gbSCXLine, gbSCXLine[299], sizeof(gbSCXLine)); + memset(gbBgpLine, gbBgpLine[299], sizeof(gbBgpLine)); + memset(gbObp0Line, gbObp0Line[299], sizeof(gbObp0Line)); + memset(gbObp1Line, gbObp1Line[299], sizeof(gbObp1Line)); + memset(gbSpritesTicks, gbSpritesTicks[299], sizeof(gbSpritesTicks)); - if (!((gbLcdMode != 1) && (register_LY==0))) - { - { - gbInt48Signal &= ~8; - gbCompareLYToLYC(); - if ((gbInt48Signal == 8) && (!((register_LY == 0) && (gbHardware & 1)))) - gbInterruptLaunched |= 2; - if ((gbHardware & (gbSpeed ? 8 : 2)) && (register_LY==0) && ((register_STAT & 0x44) == 0x44) && (gbLcdLYIncrementTicksDelayed==0)) - { - gbInterruptWait = 1; + if (gbWindowLine < 0) + oldRegister_WY = register_WY; + // check if we reached the V-Blank period + if (register_LY == 144) { + // Yes, V-Blank + // set the LY increment counter - } - } - } - gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS; + if (register_LCDC & 0x80) { + if (gbHardware & 0xa) { - if (gbLcdModeDelayed == 1) - { + register_IF |= 1; // V-Blank interrupt + gbInterruptLaunched |= 1; + } + } - if(register_LY == 153) - gbLcdLYIncrementTicksDelayed -= GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; - else if(register_LY == 0) - gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; - } - gbMemory[0xff0f] = register_IF; - gbMemory[0xff41] = register_STAT; - } - } - gbMemory[0xff0f] = register_IF; - gbMemory[0xff41] = register_STAT = (register_STAT & 0xfc) | gbLcdModeDelayed; - } - else - { + gbLcdTicksDelayed += GBLCD_MODE_1_CLOCK_TICKS; + gbLcdModeDelayed = 1; - // Used to update the screen with white lines when it's off. - // (it looks strange, but it's kinda accurate :p) - // You can try the Mario Demo Vx.x for exemple - // (check the bottom 2 lines while moving) - if (!gbWhiteScreen) - { - gbScreenTicks -= clockTicks; - gbLcdLYIncrementTicks -= clockTicks; - while (gbLcdLYIncrementTicks <=0) - { - register_LY = ((register_LY+1)%154); - gbLcdLYIncrementTicks+=GBLY_INCREMENT_CLOCK_TICKS; - } - if (gbScreenTicks <= 0) - { - gbWhiteScreen = 1; - uint8_t register_LYLcdOff = ((register_LY+154)%154); - for (register_LY=0;register_LY <= 0x90;register_LY++) - { - uint16_t color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF; - for(int i = 0; i < 160; i++) - { - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - gbDrawLine(); - } - register_LY = register_LYLcdOff; - } - } + gbFrameCount++; + systemFrame(); - if (gbWhiteScreen) - { - gbLcdLYIncrementTicks -= clockTicks; + if ((gbFrameCount % 10) == 0) + system10Frames(60); - while (gbLcdLYIncrementTicks <=0) - { - register_LY = ((register_LY+1)%154); - gbLcdLYIncrementTicks+=GBLY_INCREMENT_CLOCK_TICKS; - if (register_LY<144) - { + if (gbFrameCount >= 60) { + uint32_t currentTime = systemGetClock(); + if (currentTime != gbLastTime) + systemShowSpeed(100000 / (currentTime - gbLastTime)); + else + systemShowSpeed(0); + gbLastTime = currentTime; + gbFrameCount = 0; + } - uint16_t color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF; - for(int i = 0; i < 160; i++) - { - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - gbDrawLine(); - } - else if ((register_LY==144) && (!systemFrameSkip)) - { - int framesToSkip = systemFrameSkip; - if(speedup) - framesToSkip = 9; // try 6 FPS during speedup - if((gbFrameSkipCount >= framesToSkip) || (gbWhiteScreen == 1)) { - gbWhiteScreen = 2; + if (systemReadJoypads()) { + // read joystick + if (gbSgbMode && gbSgbMultiplayer) { + if (gbSgbFourPlayers) { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + gbJoymask[2] = systemReadJoypad(2); + gbJoymask[3] = systemReadJoypad(3); + } else { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + } + } else { + gbJoymask[0] = systemReadJoypad(-1); + } + } + int newmask = gbJoymask[0] & 255; - if(!gbSgbMask) - { - if (gbBorderOn) - gbSgbRenderBorder(); - //if (gbScreenOn) - systemDrawScreen(); - if(systemPauseOnFrame()) - ticksToStop = 0; - } - } - if(systemReadJoypads()) { - // read joystick - if(gbSgbMode && gbSgbMultiplayer) { - if(gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); + if (gbRomType == 0x22) { + systemUpdateMotionSensor(); + } + + if (newmask) { + gbMemory[0xff0f] = register_IF |= 16; + } + + newmask = (gbJoymask[0] >> 10); + + speedup = (newmask & 1) ? true : false; + gbCapture = (newmask & 2) ? true : false; + + if (gbCapture && !gbCapturePrevious) { + gbCaptureNumber++; + systemScreenCapture(gbCaptureNumber); + } + gbCapturePrevious = gbCapture; + + if (gbFrameSkipCount >= framesToSkip) { + + if (!gbSgbMask) { + if (gbBorderOn) + gbSgbRenderBorder(); + //if (gbScreenOn) + systemDrawScreen(); + if (systemPauseOnFrame()) + ticksToStop = 0; + } + gbFrameSkipCount = 0; + } else + gbFrameSkipCount++; + + } else { + // go the the OAM being accessed mode + gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdModeDelayed = 2; + gbInt48Signal &= ~3; + } + } break; + case 1: { + // V-Blank + // next mode is OAM being accessed mode + + // gbScreenOn = true; + + oldRegister_WY = register_WY; + + gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdModeDelayed = 2; + + // reset the window line + gbWindowLine = -1; + } break; + case 2: { + // OAM being accessed mode + // next mode is OAM and VRAM in use + gbLcdTicksDelayed += GBLCD_MODE_3_CLOCK_TICKS + gbSpritesTicks[299]; + gbLcdModeDelayed = 3; + } break; + case 3: { + + // OAM and VRAM in use + // next mode is H-Blank + if ((register_LY < 144) && (register_LCDC & 0x80) && gbScreenOn) { + if (!gbSgbMask) { + if (gbFrameSkipCount >= framesToSkip) { + if (!gbBlackScreen) { + gbRenderLine(); + gbDrawSprites(true); + } else if (gbBlackScreen) { + uint16_t color = gbColorOption ? gbColorFilter[0] : 0; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[3] & 0x7FFF] : gbPalette[3] & 0x7FFF; + for (int i = 0; i < 160; i++) { + gbLineMix[i] = color; + gbLineBuffer[i] = 0; + } + } + gbDrawLine(); + } + } + } + gbLcdTicksDelayed += GBLCD_MODE_0_CLOCK_TICKS - gbSpritesTicks[299]; + gbLcdModeDelayed = 0; + } break; + } + } + + if ((gbLcdLYIncrementTicksDelayed <= 0) && (gbLYChangeHappened == true)) { + + gbLYChangeHappened = false; + + if (!((gbLcdMode != 1) && (register_LY == 0))) { + { + gbInt48Signal &= ~8; + gbCompareLYToLYC(); + if ((gbInt48Signal == 8) && (!((register_LY == 0) && (gbHardware & 1)))) + gbInterruptLaunched |= 2; + if ((gbHardware & (gbSpeed ? 8 : 2)) && (register_LY == 0) && ((register_STAT & 0x44) == 0x44) && (gbLcdLYIncrementTicksDelayed == 0)) { + gbInterruptWait = 1; + } + } + } + gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS; + + if (gbLcdModeDelayed == 1) { + + if (register_LY == 153) + gbLcdLYIncrementTicksDelayed -= GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; + else if (register_LY == 0) + gbLcdLYIncrementTicksDelayed += GBLY_INCREMENT_CLOCK_TICKS - gbLine99Ticks; + } + gbMemory[0xff0f] = register_IF; + gbMemory[0xff41] = register_STAT; } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } } - gbFrameCount++; + gbMemory[0xff0f] = register_IF; + gbMemory[0xff41] = register_STAT = (register_STAT & 0xfc) | gbLcdModeDelayed; + } else { - systemFrame(); - - if((gbFrameCount % 10) == 0) - system10Frames(60); - - if(gbFrameCount >= 60) { - uint32_t currentTime = systemGetClock(); - if(currentTime != gbLastTime) - systemShowSpeed(100000/(currentTime - gbLastTime)); - else - systemShowSpeed(0); - gbLastTime = currentTime; - gbFrameCount = 0; + // Used to update the screen with white lines when it's off. + // (it looks strange, but it's kinda accurate :p) + // You can try the Mario Demo Vx.x for exemple + // (check the bottom 2 lines while moving) + if (!gbWhiteScreen) { + gbScreenTicks -= clockTicks; + gbLcdLYIncrementTicks -= clockTicks; + while (gbLcdLYIncrementTicks <= 0) { + register_LY = ((register_LY + 1) % 154); + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; + } + if (gbScreenTicks <= 0) { + gbWhiteScreen = 1; + uint8_t register_LYLcdOff = ((register_LY + 154) % 154); + for (register_LY = 0; register_LY <= 0x90; register_LY++) { + uint16_t color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF; + for (int i = 0; i < 160; i++) { + gbLineMix[i] = color; + gbLineBuffer[i] = 0; + } + gbDrawLine(); + } + register_LY = register_LYLcdOff; + } + } + + if (gbWhiteScreen) { + gbLcdLYIncrementTicks -= clockTicks; + + while (gbLcdLYIncrementTicks <= 0) { + register_LY = ((register_LY + 1) % 154); + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; + if (register_LY < 144) { + + uint16_t color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF; + for (int i = 0; i < 160; i++) { + gbLineMix[i] = color; + gbLineBuffer[i] = 0; + } + gbDrawLine(); + } else if ((register_LY == 144) && (!systemFrameSkip)) { + int framesToSkip = systemFrameSkip; + if (speedup) + framesToSkip = 9; // try 6 FPS during speedup + if ((gbFrameSkipCount >= framesToSkip) || (gbWhiteScreen == 1)) { + gbWhiteScreen = 2; + + if (!gbSgbMask) { + if (gbBorderOn) + gbSgbRenderBorder(); + //if (gbScreenOn) + systemDrawScreen(); + if (systemPauseOnFrame()) + ticksToStop = 0; + } + } + if (systemReadJoypads()) { + // read joystick + if (gbSgbMode && gbSgbMultiplayer) { + if (gbSgbFourPlayers) { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + gbJoymask[2] = systemReadJoypad(2); + gbJoymask[3] = systemReadJoypad(3); + } else { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + } + } else { + gbJoymask[0] = systemReadJoypad(-1); + } + } + gbFrameCount++; + + systemFrame(); + + if ((gbFrameCount % 10) == 0) + system10Frames(60); + + if (gbFrameCount >= 60) { + uint32_t currentTime = systemGetClock(); + if (currentTime != gbLastTime) + systemShowSpeed(100000 / (currentTime - gbLastTime)); + else + systemShowSpeed(0); + gbLastTime = currentTime; + gbFrameCount = 0; + } + } + } } - } } - } - } - gbMemory[0xff41] = register_STAT; + gbMemory[0xff41] = register_STAT; #ifndef NO_LINK - // serial emulation - gbSerialOn = (gbMemory[0xff02] & 0x80); - static int SIOctr = 0; - SIOctr++; - if (SIOctr % 5) - //Transfer Started - if (gbSerialOn && (GetLinkMode() == LINK_GAMEBOY_IPC || GetLinkMode() == LINK_GAMEBOY_SOCKET)) { + // serial emulation + gbSerialOn = (gbMemory[0xff02] & 0x80); + static int SIOctr = 0; + SIOctr++; + if (SIOctr % 5) + //Transfer Started + if (gbSerialOn && (GetLinkMode() == LINK_GAMEBOY_IPC || GetLinkMode() == LINK_GAMEBOY_SOCKET)) { #ifdef OLD_GB_LINK - if (linkConnected) { - gbSerialTicks -= clockTicks; + 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; - gbMemory[0xff0f] = register_IF |= 8; - gbSerialTicks = 0; - } - } - gbSerialTicks += GBSERIAL_CLOCK_TICKS; - } - } - else { + 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; + gbMemory[0xff0f] = register_IF |= 8; + gbSerialTicks = 0; + } + } + gbSerialTicks += GBSERIAL_CLOCK_TICKS; + } + } else { #endif - if (gbMemory[0xff02] & 1) { //internal clocks (master) - gbSerialTicks -= clockTicks; + if (gbMemory[0xff02] & 1) { //internal clocks (master) + 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 - gbSerialTicks = 0; - gbSerialBits = 0; - } - else - gbSerialTicks += GBSERIAL_CLOCK_TICKS; - } - } - else //external clocks (slave) - { - 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 + gbSerialTicks = 0; + gbSerialBits = 0; + } else + gbSerialTicks += GBSERIAL_CLOCK_TICKS; + } + } else //external clocks (slave) + { + 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 - uint16_t dat = 0; - if (LinkIsWaiting) - if (gbSerialFunction) { // external device - gbSIO_SC = gbMemory[0xff02]; - if (!LinkFirstTime) - { - dat = (gbSerialFunction(gbMemory[0xff01]) << 8) | 1; - } - else //external clock not suppose to start a transfer, but there are time where both side using external clock and couldn't communicate properly - { - if (gbMemory) - gbSerialOn = (gbMemory[0xff02] & 0x80); - dat = gbLinkUpdate(gbMemory[0xff01], gbSerialOn); - } - gbMemory[0xff01] = (dat >> 8); - } //else - gbSerialTicks = 0; - if ((dat & 1) && (gbMemory[0xff02] & 0x80)) //(dat & 1)==1 when reply data received - { - gbMemory[0xff02] &= 0x7f; - gbSerialOn = 0; - gbMemory[0xff0f] = register_IF |= 8; - } - gbSerialBits = 0; - } - else - gbSerialTicks += GBSERIAL_CLOCK_TICKS; - } - } + // 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 + uint16_t dat = 0; + if (LinkIsWaiting) + if (gbSerialFunction) { // external device + gbSIO_SC = gbMemory[0xff02]; + if (!LinkFirstTime) { + dat = (gbSerialFunction(gbMemory[0xff01]) << 8) | 1; + } else //external clock not suppose to start a transfer, but there are time where both side using external clock and couldn't communicate properly + { + if (gbMemory) + gbSerialOn = (gbMemory[0xff02] & 0x80); + dat = gbLinkUpdate(gbMemory[0xff01], gbSerialOn); + } + gbMemory[0xff01] = (dat >> 8); + } //else + gbSerialTicks = 0; + if ((dat & 1) && (gbMemory[0xff02] & 0x80)) //(dat & 1)==1 when reply data received + { + gbMemory[0xff02] &= 0x7f; + gbSerialOn = 0; + gbMemory[0xff0f] = register_IF |= 8; + } + gbSerialBits = 0; + } else + gbSerialTicks += GBSERIAL_CLOCK_TICKS; + } + } #ifdef OLD_GB_LINK - } + } #endif - } -#endif - - soundTicks -= clockTicks; - if ( !gbSpeed ) - soundTicks -= clockTicks; - - while(soundTicks < 0) { - soundTicks += SOUND_CLOCK_TICKS; - - gbSoundTick(); - } - - - // timer emulation - - if(gbTimerOn) { - gbTimerTicks= ((gbInternalTimer) & gbTimerMask[gbTimerMode])+1-clockTicks; - - while(gbTimerTicks <= 0) { - register_TIMA++; - // timer overflow! - if((register_TIMA & 0xff) == 0) { - // reload timer modulo - register_TIMA = register_TMA; - // flag interrupt - gbMemory[0xff0f] = register_IF |= 4; - } - gbTimerTicks += gbTimerClockTicks; - } - gbTimerOnChange = false; - gbTimerModeChange = false; - - gbMemory[0xff05] = register_TIMA; - - } - - gbInternalTimer -= clockTicks; - while (gbInternalTimer<0) - gbInternalTimer+=0x100; - - clockTicks = 0; - - if (gbIntBreak == 1) - { - gbIntBreak = 0; - if ((register_IE & register_IF & gbInterruptLaunched & 0x3) && - ((IFF & 0x81) == 1) && (!gbInterruptWait) && (execute)) - { - gbIntBreak = 2; - PC.W = oldPCW; - execute = false; - gbOldClockTicks = 0; - } - if (gbOldClockTicks) - { - clockTicks = gbOldClockTicks; - gbOldClockTicks = 0; - goto gbRedoLoop; - } - } - - // Executes the opcode(s), and apply the instruction's remaining clockTicks (if any). - if (execute) - { - switch(opcode1) { - case 0xCB: - // extended opcode - switch(opcode2) { -#include "gbCodesCB.h" - } - break; -#include "gbCodes.h" - } - execute = false; - - if (clockTicks) - { - gbDmaTicks += clockTicks; - clockTicks = 0; - } - } - - if (gbDmaTicks) - { - clockTicks = gbGetNextEvent(gbDmaTicks); - - if (clockTicks<=gbDmaTicks) - gbDmaTicks -= clockTicks; - else - { - clockTicks = gbDmaTicks; - gbDmaTicks = 0; - } - - goto gbRedoLoop; - } - - - // Remove the 'if an IE is pending' flag if IE has finished being executed. - if ((IFF & 0x40) && !(IFF & 0x30)) - IFF &= 0x81; - - - - if ((register_IE & register_IF & 0x1f) && (IFF & 0x81) && (!gbInterruptWait)) - { - - if (IFF & 1) - { - // Add 5 ticks for the interrupt execution time - gbDmaTicks += 5; - - if (gbIntBreak == 2) - { - gbDmaTicks--; - gbIntBreak = 0; - } - - - if(register_IF & register_IE & 1) - gbVblank_interrupt(); - else if(register_IF & register_IE & 2) - gbLcd_interrupt(); - else if(register_IF & register_IE & 4) - gbTimer_interrupt(); - else if(register_IF & register_IE & 8) - gbSerial_interrupt(); - else if(register_IF & register_IE & 16) - gbJoypad_interrupt(); - } - - IFF &= ~0x81; - } - - if (IFF & 0x08) - IFF &=~0x79; - - // Used to apply the interrupt's execution time. - if (gbDmaTicks) - { - clockTicks = gbGetNextEvent(gbDmaTicks); - - if (clockTicks<=gbDmaTicks) - gbDmaTicks -= clockTicks; - else - { - clockTicks = gbDmaTicks; - gbDmaTicks = 0; - } - goto gbRedoLoop; - } - - - gbBlackScreen = false; - - if((ticksToStop <= 0)) { - if(!(register_LCDC & 0x80)) { - if(systemReadJoypads()) { - // read joystick - if(gbSgbMode && gbSgbMultiplayer) { - if(gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } +#endif + + soundTicks -= clockTicks; + if (!gbSpeed) + soundTicks -= clockTicks; + + while (soundTicks < 0) { + soundTicks += SOUND_CLOCK_TICKS; + + gbSoundTick(); + } + + // timer emulation + + if (gbTimerOn) { + gbTimerTicks = ((gbInternalTimer)&gbTimerMask[gbTimerMode]) + 1 - clockTicks; + + while (gbTimerTicks <= 0) { + register_TIMA++; + // timer overflow! + if ((register_TIMA & 0xff) == 0) { + // reload timer modulo + register_TIMA = register_TMA; + // flag interrupt + gbMemory[0xff0f] = register_IF |= 4; + } + gbTimerTicks += gbTimerClockTicks; + } + gbTimerOnChange = false; + gbTimerModeChange = false; + + gbMemory[0xff05] = register_TIMA; + } + + gbInternalTimer -= clockTicks; + while (gbInternalTimer < 0) + gbInternalTimer += 0x100; + + clockTicks = 0; + + if (gbIntBreak == 1) { + gbIntBreak = 0; + if ((register_IE & register_IF & gbInterruptLaunched & 0x3) && ((IFF & 0x81) == 1) && (!gbInterruptWait) && (execute)) { + gbIntBreak = 2; + PC.W = oldPCW; + execute = false; + gbOldClockTicks = 0; + } + if (gbOldClockTicks) { + clockTicks = gbOldClockTicks; + gbOldClockTicks = 0; + goto gbRedoLoop; + } + } + + // Executes the opcode(s), and apply the instruction's remaining clockTicks (if any). + if (execute) { + switch (opcode1) { + case 0xCB: + // extended opcode + switch (opcode2) { +#include "gbCodesCB.h" + } + break; +#include "gbCodes.h" + } + execute = false; + + if (clockTicks) { + gbDmaTicks += clockTicks; + clockTicks = 0; + } + } + + if (gbDmaTicks) { + clockTicks = gbGetNextEvent(gbDmaTicks); + + if (clockTicks <= gbDmaTicks) + gbDmaTicks -= clockTicks; + else { + clockTicks = gbDmaTicks; + gbDmaTicks = 0; + } + + goto gbRedoLoop; + } + + // Remove the 'if an IE is pending' flag if IE has finished being executed. + if ((IFF & 0x40) && !(IFF & 0x30)) + IFF &= 0x81; + + if ((register_IE & register_IF & 0x1f) && (IFF & 0x81) && (!gbInterruptWait)) { + + if (IFF & 1) { + // Add 5 ticks for the interrupt execution time + gbDmaTicks += 5; + + if (gbIntBreak == 2) { + gbDmaTicks--; + gbIntBreak = 0; + } + + if (register_IF & register_IE & 1) + gbVblank_interrupt(); + else if (register_IF & register_IE & 2) + gbLcd_interrupt(); + else if (register_IF & register_IE & 4) + gbTimer_interrupt(); + else if (register_IF & register_IE & 8) + gbSerial_interrupt(); + else if (register_IF & register_IE & 16) + gbJoypad_interrupt(); + } + + IFF &= ~0x81; + } + + if (IFF & 0x08) + IFF &= ~0x79; + + // Used to apply the interrupt's execution time. + if (gbDmaTicks) { + clockTicks = gbGetNextEvent(gbDmaTicks); + + if (clockTicks <= gbDmaTicks) + gbDmaTicks -= clockTicks; + else { + clockTicks = gbDmaTicks; + gbDmaTicks = 0; + } + goto gbRedoLoop; + } + + gbBlackScreen = false; + + if ((ticksToStop <= 0)) { + if (!(register_LCDC & 0x80)) { + if (systemReadJoypads()) { + // read joystick + if (gbSgbMode && gbSgbMultiplayer) { + if (gbSgbFourPlayers) { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + gbJoymask[2] = systemReadJoypad(2); + gbJoymask[3] = systemReadJoypad(3); + } else { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + } + } else { + gbJoymask[0] = systemReadJoypad(-1); + } + } + } + return; } - } - return; } - } } struct EmulatedSystem GBSystem = { - // emuMain - gbEmulate, - // emuReset - gbReset, - // emuCleanUp - gbCleanUp, - // emuReadBattery - gbReadBatteryFile, - // emuWriteBattery - gbWriteBatteryFile, - // emuReadState - gbReadSaveState, - // emuWriteState - gbWriteSaveState, - // emuReadMemState - gbReadMemSaveState, - // emuWriteMemState - gbWriteMemSaveState, - // emuWritePNG - gbWritePNGFile, - // emuWriteBMP - gbWriteBMPFile, - // emuUpdateCPSR - NULL, - // emuHasDebugger - false, - // emuCount + // emuMain + gbEmulate, + // emuReset + gbReset, + // emuCleanUp + gbCleanUp, + // emuReadBattery + gbReadBatteryFile, + // emuWriteBattery + gbWriteBatteryFile, + // emuReadState + gbReadSaveState, + // emuWriteState + gbWriteSaveState, + // emuReadMemState + gbReadMemSaveState, + // emuWriteMemState + gbWriteMemSaveState, + // emuWritePNG + gbWritePNGFile, + // emuWriteBMP + gbWriteBMPFile, + // emuUpdateCPSR + NULL, + // emuHasDebugger + false, +// emuCount #ifdef FINAL_VERSION - 70000/4, + 70000 / 4, #else - 1000, + 1000, #endif }; diff --git a/src/gb/gb.h b/src/gb/gb.h index 4c4a3d8a..9ad68997 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -7,41 +7,41 @@ #define Z_FLAG 0x80 typedef union { - struct { + struct { #ifdef WORDS_BIGENDIAN - uint8_t B1, B0; + uint8_t B1, B0; #else - uint8_t B0, B1; + uint8_t B0, B1; #endif - } B; - uint16_t W; + } B; + uint16_t W; } gbRegister; extern gbRegister AF, BC, DE, HL, SP, PC; extern uint16_t IFF; -int gbDis(char *, u16); +int gbDis(char*, u16); -bool gbLoadRom(const char *); +bool gbLoadRom(const char*); bool gbUpdateSizes(); void gbEmulate(int); void gbWriteMemory(register uint16_t, register uint8_t); void gbDrawLine(); -bool gbIsGameboyRom(const char *); +bool gbIsGameboyRom(const char*); void gbGetHardwareType(); void gbReset(); void gbCleanUp(); -void gbCPUInit(const char *, bool); -bool gbWriteBatteryFile(const char *); -bool gbWriteBatteryFile(const char *, bool); -bool gbReadBatteryFile(const char *); -bool gbWriteSaveState(const char *); -bool gbWriteMemSaveState(char *, int, long &); -bool gbReadSaveState(const char *); -bool gbReadMemSaveState(char *, int); +void gbCPUInit(const char*, bool); +bool gbWriteBatteryFile(const char*); +bool gbWriteBatteryFile(const char*, bool); +bool gbReadBatteryFile(const char*); +bool gbWriteSaveState(const char*); +bool gbWriteMemSaveState(char*, int, long&); +bool gbReadSaveState(const char*); +bool gbReadMemSaveState(char*, int); void gbSgbRenderBorder(); -bool gbWritePNGFile(const char *); -bool gbWriteBMPFile(const char *); -bool gbReadGSASnapshot(const char *); +bool gbWritePNGFile(const char*); +bool gbWriteBMPFile(const char*); +bool gbReadGSASnapshot(const char*); extern int gbHardware; diff --git a/src/gb/gbCheats.cpp b/src/gb/gbCheats.cpp index 8781f488..1d5b3c18 100644 --- a/src/gb/gbCheats.cpp +++ b/src/gb/gbCheats.cpp @@ -1,532 +1,505 @@ -#include +#include #include #include -#include +#include -#include "../System.h" #include "../NLS.h" +#include "../System.h" #include "../Util.h" +#include "../common/ConfigManager.h" +#include "gb.h" #include "gbCheats.h" #include "gbGlobals.h" -#include "gb.h" -#include "../common/ConfigManager.h" gbCheat gbCheatList[MAX_CHEATS]; int gbCheatNumber = 0; int gbNextCheat = 0; bool gbCheatMap[0x10000]; -#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') +#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); + memset(gbCheatMap, 0, 0x10000); - for(int i = 0; i < gbCheatNumber; i++) { - if(gbCheatList[i].enabled) - gbCheatMap[gbCheatList[i].address] = true; - } + 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>0) - utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); + utilWriteInt(gzFile, gbCheatNumber); + if (gbCheatNumber > 0) + utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat) * gbCheatNumber); } void gbCheatsReadGame(gzFile gzFile, int version) { - if(version <= 8) { - int gbGgOn = utilReadInt(gzFile); + 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); - } + 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 > 0) { + utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat) * gbCheatNumber); + } } - 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>0) { - utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); - } - } - - gbCheatUpdateMap(); + gbCheatUpdateMap(); } - void gbCheatsReadGameSkip(gzFile gzFile, int version) { - if( version <= 8 ) { - int gbGgOn = utilReadInt( gzFile ); - if( gbGgOn ) { - int n = utilReadInt( gzFile ); - if( n > 0 ) { - utilGzSeek( gzFile, n * sizeof(gbXxCheat), SEEK_CUR ); - } - } + if (version <= 8) { + int gbGgOn = utilReadInt(gzFile); + if (gbGgOn) { + int n = utilReadInt(gzFile); + if (n > 0) { + utilGzSeek(gzFile, n * sizeof(gbXxCheat), SEEK_CUR); + } + } - int gbGsOn = utilReadInt( gzFile ); - if( gbGsOn ) { - int n = utilReadInt(gzFile); - if( n > 0 ) { - utilGzSeek( gzFile, n * sizeof(gbXxCheat), SEEK_CUR ); - } - } - } else { - int n = utilReadInt( gzFile ); + int gbGsOn = utilReadInt(gzFile); + if (gbGsOn) { + int n = utilReadInt(gzFile); + if (n > 0) { + utilGzSeek(gzFile, n * sizeof(gbXxCheat), SEEK_CUR); + } + } + } else { + int n = utilReadInt(gzFile); - if( n > 0 ) { - utilGzSeek( gzFile, n * sizeof(gbCheat), SEEK_CUR ); + if (n > 0) { + utilGzSeek(gzFile, n * sizeof(gbCheat), SEEK_CUR); + } } - } } - -void gbCheatsSaveCheatList(const char *file) +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(gbCheat) * gbCheatNumber, f); - fclose(f); + 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(gbCheat) * gbCheatNumber, f); + fclose(f); } -bool gbCheatsLoadCheatList(const char *file) +bool gbCheatsLoadCheatList(const char* file) { - gbCheatNumber = 0; + gbCheatNumber = 0; - gbCheatUpdateMap(); + gbCheatUpdateMap(); - int count = 0; + int count = 0; - FILE *f = fopen(file, "rb"); + FILE* f = fopen(file, "rb"); - if(f == NULL) - return false; + if (f == NULL) + return false; - int version = 0; + int version = 0; - if(fread(&version, 1, sizeof(version), f) != sizeof(version)) { - fclose(f); - return false; - } + 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; - } + 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; - } + 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 (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(&count, 1, sizeof(count), f) != sizeof(count)) { + fclose(f); + return false; + } - if(fread(gbCheatList, 1, sizeof(gbCheatList), f) > sizeof(gbCheatList)) { - fclose(f); - return false; - } + if (fread(gbCheatList, 1, sizeof(gbCheatList), f) > sizeof(gbCheatList)) { + fclose(f); + return false; + } - gbCheatNumber = count; - gbCheatUpdateMap(); + gbCheatNumber = count; + gbCheatUpdateMap(); - return true; -} - -bool gbVerifyGsCode(const char *code) -{ - size_t len = strlen(code); - - if(len == 0) return true; +} - if(len != 8) - return false; +bool gbVerifyGsCode(const char* code) +{ + size_t len = strlen(code); - for(int i = 0; i < 8; i++) - if(!GBCHEAT_IS_HEX(code[i])) - return false; + if (len == 0) + return true; -/* int address = GBCHEAT_HEX_VALUE(code[6]) << 12 | + 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]);*/ - return true; -} - -bool gbAddGsCheat(const char *code, const char *desc) -{ - if(gbCheatNumber > (MAX_CHEATS - 1)) { - systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, - N_("Maximum number of cheats reached.")); - return false; - } - - if(!gbVerifyGsCode(code)) { - systemMessage(MSG_INVALID_GAMESHARK_CODE, - N_("Invalid GameShark code: %s"), code); - return false; - } - - 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; - - int gsCode = gbCheatList[i].code; - - if ((gsCode !=1) && ((gsCode & 0xF0) !=0x80) && ((gsCode & 0xF0) !=0x90) && - ((gsCode & 0xF0) !=0xA0) && ((gsCode) !=0xF0) && ((gsCode) !=0xF1)) - systemMessage(MSG_WRONG_GAMESHARK_CODE, - N_("Wrong GameShark code type : %s"), code); - else if (((gsCode & 0xF0) ==0xA0) || ((gsCode) ==0xF0) || ((gsCode) ==0xF1)) - systemMessage(MSG_UNSUPPORTED_GAMESHARK_CODE, - N_("Unsupported GameShark code type : %s"), code); - - gbCheatNumber++; - - return true; -} - -bool gbVerifyGgCode(const char *code) -{ - size_t 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])) +bool gbAddGsCheat(const char* code, const char* desc) +{ + if (gbCheatNumber > (MAX_CHEATS - 1)) { + systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, + N_("Maximum number of cheats reached.")); return false; } - } - // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) + - // GBCHEAT_HEX_VALUE(code[1]); + if (!gbVerifyGsCode(code)) { + systemMessage(MSG_INVALID_GAMESHARK_CODE, + N_("Invalid GameShark code: %s"), code); + return false; + } - 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); + int i = gbCheatNumber; - if(address >= 0x8000 && address <= 0x9fff) - return false; + strcpy(gbCheatList[i].cheatCode, code); + strcpy(gbCheatList[i].cheatDesc, desc); - if(address >= 0xc000) - return false; + 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; + + int gsCode = gbCheatList[i].code; + + if ((gsCode != 1) && ((gsCode & 0xF0) != 0x80) && ((gsCode & 0xF0) != 0x90) && ((gsCode & 0xF0) != 0xA0) && ((gsCode) != 0xF0) && ((gsCode) != 0xF1)) + systemMessage(MSG_WRONG_GAMESHARK_CODE, + N_("Wrong GameShark code type : %s"), code); + else if (((gsCode & 0xF0) == 0xA0) || ((gsCode) == 0xF0) || ((gsCode) == 0xF1)) + systemMessage(MSG_UNSUPPORTED_GAMESHARK_CODE, + N_("Unsupported GameShark code type : %s"), code); + + gbCheatNumber++; - 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; } -bool gbAddGgCheat(const char *code, const char *desc) +bool gbVerifyGgCode(const char* code) { - if(gbCheatNumber > (MAX_CHEATS - 1)) { - systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, - N_("Maximum number of cheats reached.")); - return false; - } + size_t len = strlen(code); - if(!gbVerifyGgCode(code)) { - systemMessage(MSG_INVALID_GAMEGENIE_CODE, - N_("Invalid GameGenie code: %s"), code); - return false; - } + if (len != 11 && len != 7 && len != 6 && len != 0) + return false; - int i = gbCheatNumber; + if (len == 0) + return true; - size_t len = strlen(code); + 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; + } + } - strcpy(gbCheatList[i].cheatCode, code); - strcpy(gbCheatList[i].cheatDesc, desc); + // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) + + // GBCHEAT_HEX_VALUE(code[1]); - gbCheatList[i].code = 0x101; - gbCheatList[i].value = (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); - 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); + if (address >= 0x8000 && address <= 0x9fff) + return false; - gbCheatList[i].compare = 0; + if (address >= 0xc000) + return false; - if(len != 7 && len != 8) { + if (code[7] == 0 || code[8] == '0') + return true; - int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) + - (GBCHEAT_HEX_VALUE(code[10])); + int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) + (GBCHEAT_HEX_VALUE(code[10])); compare = compare ^ 0xff; - compare = (compare >> 2) | ( (compare << 6) & 0xc0); + compare = (compare >> 2) | ((compare << 6) & 0xc0); compare ^= 0x45; - gbCheatList[i].compare = compare; - //gbCheatList[i].code = 0; - gbCheatList[i].code = 0x100; // fix for compare value + int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9])); - } + if (cloak >= 1 && cloak <= 7) + return false; + return true; +} - gbCheatList[i].enabled = true; +bool gbAddGgCheat(const char* code, const char* desc) +{ + if (gbCheatNumber > (MAX_CHEATS - 1)) { + systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS, + N_("Maximum number of cheats reached.")); + return false; + } - gbCheatMap[gbCheatList[i].address] = true; + if (!gbVerifyGgCode(code)) { + systemMessage(MSG_INVALID_GAMEGENIE_CODE, + N_("Invalid GameGenie code: %s"), code); + return false; + } - gbCheatNumber++; + int i = gbCheatNumber; - return true; + size_t len = strlen(code); + + strcpy(gbCheatList[i].cheatCode, code); + strcpy(gbCheatList[i].cheatDesc, desc); + + gbCheatList[i].code = 0x101; + 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].code = 0x100; // fix for compare value + } + + gbCheatList[i].enabled = true; + + gbCheatMap[gbCheatList[i].address] = true; + + gbCheatNumber++; + + return true; } 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 < 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)); - } + if ((i + 1) < gbCheatNumber) { + memcpy(&gbCheatList[i], &gbCheatList[i + 1], sizeof(gbCheat) * (gbCheatNumber - i - 1)); + } - gbCheatNumber--; + gbCheatNumber--; - gbCheatUpdateMap(); + gbCheatUpdateMap(); } void gbCheatRemoveAll() { - gbCheatNumber = 0; - gbCheatUpdateMap(); + gbCheatNumber = 0; + gbCheatUpdateMap(); } void gbCheatEnable(int i) { - if(i >=0 && i < gbCheatNumber) { - if(!gbCheatList[i].enabled) { - gbCheatList[i].enabled = true; - gbCheatUpdateMap(); + 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(); + if (i >= 0 && i < gbCheatNumber) { + if (gbCheatList[i].enabled) { + gbCheatList[i].enabled = false; + gbCheatUpdateMap(); + } } - } } -bool gbCheatReadGSCodeFile(const char *fileName) +bool gbCheatReadGSCodeFile(const char* fileName) { - FILE *file = fopen(fileName, "rb"); + FILE* file = fopen(fileName, "rb"); - if(!file) { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); - return false; - } + if (!file) { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + 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); - } + 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); + for (i = 0; i < gbCheatNumber; i++) + gbCheatDisable(i); - fclose(file); - return true; + fclose(file); + return true; } // Used to emulated GG codes -u8 gbCheatRead(u16 address) +uint8_t gbCheatRead(uint16_t address) { - if(!cheatsEnabled) - return gbMemoryMap[address>>12][address & 0xFFF]; + if (!cheatsEnabled) + return gbMemoryMap[address >> 12][address & 0xFFF]; - for(int i = 0; i < gbCheatNumber; i++) { - if(gbCheatList[i].enabled && gbCheatList[i].address == address) { - switch(gbCheatList[i].code) { - case 0x100: // GameGenie support - if(gbMemoryMap[address>>12][address&0xFFF] == gbCheatList[i].compare) - return gbCheatList[i].value; - break; - case 0x101: // GameGenie 6 digits code support - return gbCheatList[i].value; - break; - } + for (int i = 0; i < gbCheatNumber; i++) { + if (gbCheatList[i].enabled && gbCheatList[i].address == address) { + switch (gbCheatList[i].code) { + case 0x100: // GameGenie support + if (gbMemoryMap[address >> 12][address & 0xFFF] == gbCheatList[i].compare) + return gbCheatList[i].value; + break; + case 0x101: // GameGenie 6 digits code support + return gbCheatList[i].value; + break; + } + } } - } - return gbMemoryMap[address>>12][address&0xFFF]; + return gbMemoryMap[address >> 12][address & 0xFFF]; } - // Used to emulate GS codes. void gbCheatWrite(bool reboot) { - if(cheatsEnabled) - { - u16 address = 0; + if (cheatsEnabled) { + u16 address = 0; - if (gbNextCheat >= gbCheatNumber) - gbNextCheat = 0; + if (gbNextCheat >= gbCheatNumber) + gbNextCheat = 0; - for(int i = gbNextCheat; i < gbCheatNumber; i++) { - if(gbCheatList[i].enabled) { - address = gbCheatList[i].address; - if ((!reboot) && (address >= 0x8000) && !((address>=0xA000) && (address<0xC000))) - { // These codes are executed one per one, at each Vblank - switch(gbCheatList[i].code) { - case 0x01: - gbWriteMemory(address, gbCheatList[i].value); - gbNextCheat = i+1; - return; - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - int oldbank = gbMemory[0xff70]; - gbWriteMemory(0xff70, gbCheatList[i].code & 0xf); - gbWriteMemory(address, gbCheatList[i].value); - gbWriteMemory(0xff70, oldbank); - gbNextCheat = i+1; - return; - } + for (int i = gbNextCheat; i < gbCheatNumber; i++) { + if (gbCheatList[i].enabled) { + address = gbCheatList[i].address; + if ((!reboot) && (address >= 0x8000) && !((address >= 0xA000) && (address < 0xC000))) { // These codes are executed one per one, at each Vblank + switch (gbCheatList[i].code) { + case 0x01: + gbWriteMemory(address, gbCheatList[i].value); + gbNextCheat = i + 1; + return; + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + int oldbank = gbMemory[0xff70]; + gbWriteMemory(0xff70, gbCheatList[i].code & 0xf); + gbWriteMemory(address, gbCheatList[i].value); + gbWriteMemory(0xff70, oldbank); + gbNextCheat = i + 1; + return; + } + } else // These codes are only executed when the game is booted + { + switch (gbCheatList[i].code & 0xF0) { + case 0x80: + gbWriteMemory(0x0000, 0x0A); + gbWriteMemory(0x4000, gbCheatList[i].value & 0xF); + gbWriteMemory(address, gbCheatList[i].value); + gbNextCheat = i + 1; + return; + } + } + } } - else // These codes are only executed when the game is booted - { - switch(gbCheatList[i].code & 0xF0) { - case 0x80: - gbWriteMemory(0x0000, 0x0A); - gbWriteMemory(0x4000, gbCheatList[i].value & 0xF); - gbWriteMemory(address, gbCheatList[i].value); - gbNextCheat = i+1; - return; - } - } - } } - } } diff --git a/src/gb/gbCheats.h b/src/gb/gbCheats.h index bc4798bf..5edea88e 100644 --- a/src/gb/gbCheats.h +++ b/src/gb/gbCheats.h @@ -5,37 +5,37 @@ #include "../common/ConfigManager.h" struct gbXxCheat { - char cheatDesc[100]; - char cheatCode[20]; + char cheatDesc[100]; + char cheatCode[20]; }; struct gbCheat { - char cheatCode[20]; - char cheatDesc[32]; - u16 address; - int code; - u8 compare; - u8 value; - bool enabled; + char cheatCode[20]; + char cheatDesc[32]; + uint16_t address; + int code; + uint8_t compare; + uint8_t value; + bool enabled; }; void gbCheatsSaveGame(gzFile); void gbCheatsReadGame(gzFile, int); void gbCheatsReadGameSkip(gzFile, int); -void gbCheatsSaveCheatList(const char *); -bool gbCheatsLoadCheatList(const char *); -bool gbCheatReadGSCodeFile(const char *); +void gbCheatsSaveCheatList(const char*); +bool gbCheatsLoadCheatList(const char*); +bool gbCheatReadGSCodeFile(const char*); -bool gbAddGsCheat(const char *, const char *); -bool gbAddGgCheat(const char *, const char *); +bool gbAddGsCheat(const char*, const char*); +bool gbAddGgCheat(const char*, const char*); void gbCheatRemove(int); void gbCheatRemoveAll(); void gbCheatEnable(int); void gbCheatDisable(int); -u8 gbCheatRead(u16); +uint8_t gbCheatRead(u16); void gbCheatWrite(bool); -bool gbVerifyGsCode(const char *code); -bool gbVerifyGgCode(const char *code); +bool gbVerifyGsCode(const char* code); +bool gbVerifyGgCode(const char* code); extern int gbCheatNumber; extern gbCheat gbCheatList[MAX_CHEATS]; diff --git a/src/gb/gbCodes.h b/src/gb/gbCodes.h index fa7be0f2..10a85d6c 100644 --- a/src/gb/gbCodes.h +++ b/src/gb/gbCodes.h @@ -22,8 +22,7 @@ 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); +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 @@ -45,8 +44,7 @@ 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); +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: @@ -65,8 +63,7 @@ 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); +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 @@ -82,15 +79,15 @@ case 0x10: // STOP opcode = gbReadOpcode(PC.W++); if (gbCgbMode) { - if (gbMemory[0xff4d] & 1) { - gbSpeedSwitch(); - // clockTicks += 228*144-(gbSpeed ? 62 : 63); + if (gbMemory[0xff4d] & 1) { + gbSpeedSwitch(); + // clockTicks += 228*144-(gbSpeed ? 62 : 63); - if (gbSpeed == 0) - gbMemory[0xff4d] = 0x00; - else - gbMemory[0xff4d] = 0x80; - } + if (gbSpeed == 0) + gbMemory[0xff4d] = 0x00; + else + gbMemory[0xff4d] = 0x80; + } } break; case 0x11: @@ -114,8 +111,7 @@ 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); +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 @@ -134,8 +130,7 @@ 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); +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: @@ -154,8 +149,7 @@ 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); +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 @@ -170,10 +164,10 @@ break; case 0x20: // JR NZ,NN if (AF.B.B0 & Z_FLAG) - PC.W++; + PC.W++; else { - PC.W += (s8)gbReadOpcode(PC.W) + 1; - clockTicks++; + PC.W += (s8)gbReadOpcode(PC.W) + 1; + clockTicks++; } break; case 0x21: @@ -197,8 +191,7 @@ 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); +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 @@ -213,16 +206,15 @@ break; case 0x28: // JR Z,NN if (AF.B.B0 & Z_FLAG) { - PC.W += (s8)gbReadOpcode(PC.W) + 1; - clockTicks++; + PC.W += (s8)gbReadOpcode(PC.W) + 1; + clockTicks++; } else - PC.W++; + 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); +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: @@ -241,8 +233,7 @@ 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); +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 @@ -256,10 +247,10 @@ break; case 0x30: // JR NC,NN if (AF.B.B0 & C_FLAG) - PC.W++; + PC.W++; else { - PC.W += (s8)gbReadOpcode(PC.W) + 1; - clockTicks++; + PC.W += (s8)gbReadOpcode(PC.W) + 1; + clockTicks++; } break; case 0x31: @@ -284,8 +275,7 @@ break; case 0x35: // DEC (HL) tempValue = gbReadMemory(HL.W) - 1; -AF.B.B0 = - N_FLAG | (AF.B.B0 & C_FLAG) | ZeroTable[tempValue] | ((tempValue & 0x0F) == 0x0F ? H_FLAG : 0); +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: @@ -299,16 +289,15 @@ break; case 0x38: // JR C,NN if (AF.B.B0 & C_FLAG) { - PC.W += (s8)gbReadOpcode(PC.W) + 1; - clockTicks++; + PC.W += (s8)gbReadOpcode(PC.W) + 1; + clockTicks++; } else - PC.W++; + 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); +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: @@ -327,8 +316,7 @@ 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); +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 @@ -560,16 +548,16 @@ case 0x76: // If an EI is pending, the interrupts are triggered before Halt state !! // Fix Torpedo Range's intro. if (IFF & 0x40) { - IFF &= ~0x70; - IFF |= 1; - PC.W--; + IFF &= ~0x70; + IFF |= 1; + PC.W--; } else { - // if (IE & IF) and interrupts are disabeld, - // Halt is cancelled. - if ((register_IE & register_IF & 0x1f) && !(IFF & 1)) { - IFF |= 2; - } else - IFF |= 0x80; + // if (IE & IF) and interrupts are disabeld, + // Halt is cancelled. + if ((register_IE & register_IF & 0x1f) && !(IFF & 1)) { + IFF |= 2; + } else + IFF |= 0x80; } break; case 0x77: @@ -611,165 +599,142 @@ 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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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: @@ -780,58 +745,50 @@ 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.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.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.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.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.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.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.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.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: @@ -960,45 +917,38 @@ 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); +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); +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); +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); +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); +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); +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); +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 @@ -1007,9 +957,9 @@ 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; + PC.B.B0 = gbReadMemory(SP.W++); + PC.B.B1 = gbReadMemory(SP.W++); + clockTicks += 3; } break; case 0xc1: @@ -1020,12 +970,12 @@ break; case 0xc2: // JP NZ,NNNN if (AF.B.B0 & Z_FLAG) - PC.W += 2; + PC.W += 2; else { - tempRegister.B.B0 = gbReadOpcode(PC.W++); - tempRegister.B.B1 = gbReadOpcode(PC.W); - PC.W = tempRegister.W; - clockTicks++; + tempRegister.B.B0 = gbReadOpcode(PC.W++); + tempRegister.B.B1 = gbReadOpcode(PC.W); + PC.W = tempRegister.W; + clockTicks++; } break; case 0xc3: @@ -1037,14 +987,14 @@ break; case 0xc4: // CALL NZ,NNNN if (AF.B.B0 & Z_FLAG) - PC.W += 2; + PC.W += 2; else { - tempRegister.B.B0 = gbReadOpcode(PC.W++); - tempRegister.B.B1 = gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = tempRegister.W; - clockTicks += 3; + tempRegister.B.B0 = gbReadOpcode(PC.W++); + tempRegister.B.B1 = gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = tempRegister.W; + clockTicks += 3; } break; case 0xc5: @@ -1056,8 +1006,7 @@ 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.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: @@ -1069,9 +1018,9 @@ 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; + PC.B.B0 = gbReadMemory(SP.W++); + PC.B.B1 = gbReadMemory(SP.W++); + clockTicks += 3; } break; case 0xc9: @@ -1082,25 +1031,25 @@ break; case 0xca: // JP Z,NNNN if (AF.B.B0 & Z_FLAG) { - tempRegister.B.B0 = gbReadOpcode(PC.W++); - tempRegister.B.B1 = gbReadOpcode(PC.W); - PC.W = tempRegister.W; - clockTicks++; + tempRegister.B.B0 = gbReadOpcode(PC.W++); + tempRegister.B.B1 = gbReadOpcode(PC.W); + PC.W = tempRegister.W; + clockTicks++; } else - PC.W += 2; + PC.W += 2; break; // CB done outside case 0xcc: // CALL Z,NNNN if (AF.B.B0 & Z_FLAG) { - tempRegister.B.B0 = gbReadOpcode(PC.W++); - tempRegister.B.B1 = gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = tempRegister.W; - clockTicks += 3; + tempRegister.B.B0 = gbReadOpcode(PC.W++); + tempRegister.B.B1 = gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = tempRegister.W; + clockTicks += 3; } else - PC.W += 2; + PC.W += 2; break; case 0xcd: // CALL NNNN @@ -1114,8 +1063,7 @@ 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.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: @@ -1127,9 +1075,9 @@ 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; + PC.B.B0 = gbReadMemory(SP.W++); + PC.B.B1 = gbReadMemory(SP.W++); + clockTicks += 3; } break; case 0xd1: @@ -1140,12 +1088,12 @@ break; case 0xd2: // JP NC,NNNN if (AF.B.B0 & C_FLAG) - PC.W += 2; + PC.W += 2; else { - tempRegister.B.B0 = gbReadOpcode(PC.W++); - tempRegister.B.B1 = gbReadOpcode(PC.W); - PC.W = tempRegister.W; - clockTicks++; + tempRegister.B.B0 = gbReadOpcode(PC.W++); + tempRegister.B.B1 = gbReadOpcode(PC.W); + PC.W = tempRegister.W; + clockTicks++; } break; // D3 illegal @@ -1156,14 +1104,14 @@ break; case 0xd4: // CALL NC,NNNN if (AF.B.B0 & C_FLAG) - PC.W += 2; + PC.W += 2; else { - tempRegister.B.B0 = gbReadOpcode(PC.W++); - tempRegister.B.B1 = gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = tempRegister.W; - clockTicks += 3; + tempRegister.B.B0 = gbReadOpcode(PC.W++); + tempRegister.B.B1 = gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = tempRegister.W; + clockTicks += 3; } break; case 0xd5: @@ -1175,8 +1123,7 @@ 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.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: @@ -1188,9 +1135,9 @@ break; case 0xd8: // RET C if (AF.B.B0 & C_FLAG) { - PC.B.B0 = gbReadMemory(SP.W++); - PC.B.B1 = gbReadMemory(SP.W++); - clockTicks += 3; + PC.B.B0 = gbReadMemory(SP.W++); + PC.B.B1 = gbReadMemory(SP.W++); + clockTicks += 3; } break; case 0xd9: @@ -1202,12 +1149,12 @@ break; case 0xda: // JP C,NNNN if (AF.B.B0 & C_FLAG) { - tempRegister.B.B0 = gbReadOpcode(PC.W++); - tempRegister.B.B1 = gbReadOpcode(PC.W); - PC.W = tempRegister.W; - clockTicks++; + tempRegister.B.B0 = gbReadOpcode(PC.W++); + tempRegister.B.B1 = gbReadOpcode(PC.W); + PC.W = tempRegister.W; + clockTicks++; } else - PC.W += 2; + PC.W += 2; break; // DB illegal case 0xdb: @@ -1217,14 +1164,14 @@ break; case 0xdc: // CALL C,NNNN if (AF.B.B0 & C_FLAG) { - tempRegister.B.B0 = gbReadOpcode(PC.W++); - tempRegister.B.B1 = gbReadOpcode(PC.W++); - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = tempRegister.W; - clockTicks += 3; + tempRegister.B.B0 = gbReadOpcode(PC.W++); + tempRegister.B.B1 = gbReadOpcode(PC.W++); + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = tempRegister.W; + clockTicks += 3; } else - PC.W += 2; + PC.W += 2; break; // DD illegal case 0xdd: @@ -1235,8 +1182,7 @@ 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.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: @@ -1286,8 +1232,7 @@ case 0xe8: // ADD SP,NN offset = (s8)gbReadOpcode(PC.W++); tempRegister.W = SP.W + offset; -AF.B.B0 = ((SP.W ^ offset ^ tempRegister.W) & 0x100 ? C_FLAG : 0) | - ((SP.W ^ offset ^ tempRegister.W) & 0x10 ? H_FLAG : 0); +AF.B.B0 = ((SP.W ^ offset ^ tempRegister.W) & 0x100 ? C_FLAG : 0) | ((SP.W ^ offset ^ tempRegister.W) & 0x10 ? H_FLAG : 0); SP.W = tempRegister.W; break; case 0xe9: @@ -1365,8 +1310,7 @@ case 0xf8: // LD HL,SP+NN offset = (s8)gbReadOpcode(PC.W++); tempRegister.W = SP.W + offset; -AF.B.B0 = ((SP.W ^ offset ^ tempRegister.W) & 0x100 ? C_FLAG : 0) | - ((SP.W ^ offset ^ tempRegister.W) & 0x10 ? H_FLAG : 0); +AF.B.B0 = ((SP.W ^ offset ^ tempRegister.W) & 0x100 ? C_FLAG : 0) | ((SP.W ^ offset ^ tempRegister.W) & 0x10 ? H_FLAG : 0); HL.W = tempRegister.W; break; case 0xf9: @@ -1382,12 +1326,12 @@ break; case 0xfb: // EI if (!(IFF & 0x30)) - // If an EI is executed right before HALT, - // the interrupts are triggered before the Halt state !! - // Fix Torpedo Range Intro. - // IFF |= 0x10 : 1 ticks before the EI enables the interrupts - // IFF |= 0x40 : marks that an EI is being executed. - IFF |= 0x50; + // If an EI is executed right before HALT, + // the interrupts are triggered before the Halt state !! + // Fix Torpedo Range Intro. + // IFF |= 0x10 : 1 ticks before the EI enables the interrupts + // IFF |= 0x40 : marks that an EI is being executed. + IFF |= 0x50; break; // FC illegal (FC = breakpoint) case 0xfc: @@ -1402,8 +1346,7 @@ 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); +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 @@ -1413,7 +1356,7 @@ PC.W = 0x0038; break; default: if (gbSystemMessage == false) { - systemMessage(0, N_("Unknown opcode %02x at %04x"), gbReadOpcode(PC.W - 1), PC.W - 1); - gbSystemMessage = true; + systemMessage(0, N_("Unknown opcode %02x at %04x"), gbReadOpcode(PC.W - 1), PC.W - 1); + gbSystemMessage = true; } return; diff --git a/src/gb/gbCodesCB.h b/src/gb/gbCodesCB.h index 02ff0561..00096036 100644 --- a/src/gb/gbCodesCB.h +++ b/src/gb/gbCodesCB.h @@ -101,165 +101,165 @@ break; case 0x10: // RL B if (BC.B.B1 & 0x80) { - BC.B.B1 = (BC.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[BC.B.B1] | C_FLAG; + BC.B.B1 = (BC.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + AF.B.B0 = ZeroTable[BC.B.B1] | C_FLAG; } else { - BC.B.B1 = (BC.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[BC.B.B1]; + BC.B.B1 = (BC.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + 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); - AF.B.B0 = ZeroTable[BC.B.B0] | C_FLAG; + BC.B.B0 = (BC.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + AF.B.B0 = ZeroTable[BC.B.B0] | C_FLAG; } else { - BC.B.B0 = (BC.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[BC.B.B0]; + BC.B.B0 = (BC.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + 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); - AF.B.B0 = ZeroTable[DE.B.B1] | C_FLAG; + DE.B.B1 = (DE.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + AF.B.B0 = ZeroTable[DE.B.B1] | C_FLAG; } else { - DE.B.B1 = (DE.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[DE.B.B1]; + DE.B.B1 = (DE.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + 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); - AF.B.B0 = ZeroTable[DE.B.B0] | C_FLAG; + DE.B.B0 = (DE.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + AF.B.B0 = ZeroTable[DE.B.B0] | C_FLAG; } else { - DE.B.B0 = (DE.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[DE.B.B0]; + DE.B.B0 = (DE.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + 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); - AF.B.B0 = ZeroTable[HL.B.B1] | C_FLAG; + HL.B.B1 = (HL.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + AF.B.B0 = ZeroTable[HL.B.B1] | C_FLAG; } else { - HL.B.B1 = (HL.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[HL.B.B1]; + HL.B.B1 = (HL.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + 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); - AF.B.B0 = ZeroTable[HL.B.B0] | C_FLAG; + HL.B.B0 = (HL.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + AF.B.B0 = ZeroTable[HL.B.B0] | C_FLAG; } else { - HL.B.B0 = (HL.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[HL.B.B0]; + HL.B.B0 = (HL.B.B0 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + 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); - AF.B.B0 = ZeroTable[tempValue] | C_FLAG; + tempValue = (tempValue << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + AF.B.B0 = ZeroTable[tempValue] | C_FLAG; } else { - tempValue = (tempValue << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[tempValue]; + tempValue = (tempValue << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + 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); - AF.B.B0 = ZeroTable[AF.B.B1] | C_FLAG; + AF.B.B1 = (AF.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + AF.B.B0 = ZeroTable[AF.B.B1] | C_FLAG; } else { - AF.B.B1 = (AF.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); - AF.B.B0 = ZeroTable[AF.B.B1]; + AF.B.B1 = (AF.B.B1 << 1) | (AF.B.B0 & C_FLAG ? 1 : 0); + 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; + 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]; + 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; + 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]; + 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; + 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]; + 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; + 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]; + 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; + 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]; + 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; + 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]; + 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; + 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]; + 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; + 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]; + AF.B.B1 = (AF.B.B1 >> 1) | (AF.B.B0 & C_FLAG ? 0x80 : 0); + AF.B.B0 = ZeroTable[AF.B.B1]; } break; case 0x20: @@ -1264,7 +1264,7 @@ AF.B.B1 |= 1 << 7; break; default: if (gbSystemMessage == false) { - systemMessage(0, N_("Unknown opcode %02x at %04x"), gbReadOpcode(PC.W - 1), PC.W - 1); - gbSystemMessage = true; + systemMessage(0, N_("Unknown opcode %02x at %04x"), gbReadOpcode(PC.W - 1), PC.W - 1); + gbSystemMessage = true; } return; diff --git a/src/gb/gbDis.cpp b/src/gb/gbDis.cpp index 15d7d7f9..e62582c6 100644 --- a/src/gb/gbDis.cpp +++ b/src/gb/gbDis.cpp @@ -5,227 +5,225 @@ #include "gbGlobals.h" typedef struct { - u8 mask; - u8 value; - const char *mnen; + uint8_t mask; + uint8_t value; + const char* mnen; } GBOPCODE; -#define GB_READ(x) gbMemoryMap[(x)>>12][(x)&0xfff] +#define GB_READ(x) gbMemoryMap[(x) >> 12][(x)&0xfff] -static const char *registers[] = - { "B", "C", "D", "E", "H", "L", "(HL)", "A" }; +static const char* registers[] = { "B", "C", "D", "E", "H", "L", "(HL)", "A" }; -static const char *registers16[] = - { "BC", "DE", "HL", "SP", // for some operations +static const char* registers16[] = { "BC", "DE", "HL", "SP", // for some operations "BC", "DE", "HL", "AF" }; // for push/pop -static const char *cond[] = - { "NZ", "Z", "NC", "C" }; +static const 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' + '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" } + { 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" } + { 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) +static char* addHex(char* p, uint8_t value) { - *p++ = hexDigits[value >> 4]; - *p++ = hexDigits[value & 15]; - return p; + *p++ = hexDigits[value >> 4]; + *p++ = hexDigits[value & 15]; + return p; } -static char *addHex16(char *p, u16 value) +static char* addHex16(char* p, uint16_t value) { - p = addHex(p, value>>8); - return addHex(p, value & 255); + p = addHex(p, value >> 8); + return addHex(p, value & 255); } -static char *addStr(char *p, const char *s) +static char* addStr(char* p, const char* s) { - while(*s) { - *p++ = *s++; - } - return p; + while (*s) { + *p++ = *s++; + } + return p; } -int gbDis(char *buffer, u16 address) +int gbDis(char* buffer, uint16_t address) { - char *p = buffer; - int instr = 1; - u16 addr = address; - sprintf(p, "%04x ", address); - p += 12; + char* p = buffer; + int instr = 1; + uint16_t addr = address; + sprintf(p, "%04x ", address); + p += 12; - u8 opcode = GB_READ(address); - address++; - const char *mnen; - GBOPCODE *op; - if(opcode == 0xcb) { - opcode = GB_READ(address); + uint8_t opcode = GB_READ(address); address++; - instr++; - op = cbOpcodes; - } else { - op = opcodes; - } - while(op->value != (opcode & op->mask)) op++; - mnen = op->mnen; + const char* mnen; + GBOPCODE* op; + if (opcode == 0xcb) { + opcode = GB_READ(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; + uint8_t b0, b1; + int8_t disp; + int shift; - while(*mnen) { - if(*mnen == '%') { - mnen++; - switch(*mnen++) { - case 'W': - b0 = GB_READ(address); - address++; - b1 = GB_READ(address); - address++; - p = addHex16(p, b0|b1<<8); - instr += 2; - *p++ = 'h'; - break; - case 'B': - p = addHex(p, GB_READ(address)); - *p++ = 'h'; - address++; - instr++; - break; - case 'D': - disp = GB_READ(address); - if(disp >= 0) - *p++ = '+'; - p += sprintf(p, "%d", disp); - instr++; - break; - case 'd': - disp = GB_READ(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, GB_READ(a)); - } - *p = 0; - return instr; + while (*mnen) { + if (*mnen == '%') { + mnen++; + switch (*mnen++) { + case 'W': + b0 = GB_READ(address); + address++; + b1 = GB_READ(address); + address++; + p = addHex16(p, b0 | b1 << 8); + instr += 2; + *p++ = 'h'; + break; + case 'B': + p = addHex(p, GB_READ(address)); + *p++ = 'h'; + address++; + instr++; + break; + case 'D': + disp = GB_READ(address); + if (disp >= 0) + *p++ = '+'; + p += sprintf(p, "%d", disp); + instr++; + break; + case 'd': + disp = GB_READ(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++) { + uint16_t a = addr + i; + addHex(buffer + 5 + i * 2, GB_READ(a)); + } + *p = 0; + return instr; } diff --git a/src/gb/gbGfx.cpp b/src/gb/gbGfx.cpp index 3e7da41f..7ad0a463 100644 --- a/src/gb/gbGfx.cpp +++ b/src/gb/gbGfx.cpp @@ -1,43 +1,43 @@ #include -#include "../common/Types.h" #include "../Util.h" +#include "../common/Types.h" #include "gbGlobals.h" #include "gbSGB.h" 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 + 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]; @@ -47,544 +47,529 @@ extern int layerSettings; void gbRenderLine() { - memset(gbLineMix, 0, sizeof(gbLineMix)); - u8 * bank0; - u8 * bank1; - if(gbCgbMode) { - bank0 = &gbVram[0x0000]; - bank1 = &gbVram[0x2000]; - } else { - bank0 = &gbMemory[0x8000]; - bank1 = NULL; - } + memset(gbLineMix, 0, sizeof(gbLineMix)); + 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_map = 0x1800; + if ((register_LCDC & 8) != 0) + tile_map = 0x1c00; - int tile_pattern = 0x0800; + int tile_pattern = 0x0800; - if((register_LCDC & 16) != 0) - tile_pattern = 0x0000; + if ((register_LCDC & 16) != 0) + tile_pattern = 0x0000; - int x = 0; - int y = register_LY; + int x = 0; + int y = register_LY; - if(y >= 144) - return; + if (y >= 144) + return; - int SpritesTicks = gbSpritesTicks[x]*(gbSpeed ? 2 : 4); - int sx = gbSCXLine[(gbSpeed ? 0 : 4)+SpritesTicks]; - int sy = gbSCYLine[(gbSpeed ? 11 : 5)+SpritesTicks]; + int SpritesTicks = gbSpritesTicks[x] * (gbSpeed ? 2 : 4); + int sx = gbSCXLine[(gbSpeed ? 0 : 4) + SpritesTicks]; + int sy = gbSCYLine[(gbSpeed ? 11 : 5) + SpritesTicks]; - sy+=y; + sy += y; - sy &= 255; + sy &= 255; - int tx = sx >> 3; - int ty = sy >> 3; + int tx = sx >> 3; + int ty = sy >> 3; - int bx = 1 << (7 - (sx & 7)); - int by = sy & 7; + int bx = 1 << (7 - (sx & 7)); + int by = sy & 7; - int tile_map_line_y = tile_map + ty * 32; + int tile_map_line_y = tile_map + ty * 32; - int tile_map_address = tile_map_line_y + tx; + int tile_map_address = tile_map_line_y + tx; - u8 attrs = 0; - if(bank1 != NULL) - attrs = bank1[tile_map_address]; + u8 attrs = 0; + if (bank1 != NULL) + attrs = bank1[tile_map_address]; - u8 tile = bank0[tile_map_address]; + u8 tile = bank0[tile_map_address]; - tile_map_address++; + tile_map_address++; - if(!(register_LCDC & 0x10)) + if (!(register_LCDC & 0x10)) tile ^= 0x80; - int tile_pattern_address = tile_pattern + tile * 16 + by*2; + int tile_pattern_address = tile_pattern + tile * 16 + by * 2; - if(register_LCDC & 0x80) { - if((register_LCDC & 0x01 || gbCgbMode) && (layerSettings & 0x0100)) { - while(x < 160) { + 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; + } - u8 tile_a = 0; - u8 tile_b = 0; + 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 & 0x40) { - tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2; - } + if (attrs & 0x20) { + tile_a = gbInvertTab[tile_a]; + tile_b = gbInvertTab[tile_b]; + } - if(attrs & 0x08) { - tile_a = bank1[tile_pattern_address++]; - tile_b = bank1[tile_pattern_address]; + 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) { + // Use the DMG palette if we are in compat mode. + if (gbMemory[0xff6c] & 1) { + c = gbBgp[c]; + } else { + c = c + (attrs & 7) * 4; + } + } else { + c = (gbBgpLine[x + (gbSpeed ? 5 : 11) + SpritesTicks] >> (c << 1)) & 3; + 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] & 0x7FFF] : gbPalette[c] & 0x7FFF; + x++; + if (x >= 160) + break; + bx >>= 1; + } + + bx = 128; + + SpritesTicks = gbSpritesTicks[x] * (gbSpeed ? 2 : 4); + + sx = gbSCXLine[x + (gbSpeed ? 0 : 4) + SpritesTicks]; + + sy = gbSCYLine[x + (gbSpeed ? 11 : 5) + SpritesTicks]; + + tx = ((sx + x) >> 3) & 0x1f; + + sy += y; + + sy &= 255; + + ty = sy >> 3; + + by = sy & 7; + + tile_pattern_address = tile_pattern + tile * 16 + by * 2; + + tile_map_line_y = tile_map + ty * 32; + + tile_map_address = tile_map_line_y + tx; + + if (bank1) + attrs = bank1[tile_map_line_y + tx]; + + tile = bank0[tile_map_line_y + tx]; + + if (!(register_LCDC & 0x10)) + tile ^= 0x80; + + tile_pattern_address = tile_pattern + tile * 16 + by * 2; + } } 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) { - // Use the DMG palette if we are in compat mode. - if (gbMemory[0xff6c] & 1) { - c = gbBgp[c]; - } else { - c = c + (attrs & 7) * 4; + // Use gbBgp[0] instead of 0 (?) + // (this fixes white flashes on Last Bible II) + // Also added the gbColorOption (fixes Dracula Densetsu II color problems) + for (int i = 0; i < 160; i++) { + u16 color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; + if (!gbCgbMode) + color = gbColorOption ? gbColorFilter[gbPalette[gbBgpLine[i + (gbSpeed ? 5 : 11) + gbSpritesTicks[i] * (gbSpeed ? 2 : 4)] & 3] & 0x7FFF] : gbPalette[gbBgpLine[i + (gbSpeed ? 5 : 11) + gbSpritesTicks[i] * (gbSpeed ? 2 : 4)] & 3] & 0x7FFF; + gbLineMix[i] = color; + gbLineBuffer[i] = 0; } - } else { - c = (gbBgpLine[x+(gbSpeed ? 5 : 11)+SpritesTicks]>>(c<<1)) &3; - 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] & 0x7FFF] : gbPalette[c] & 0x7FFF; - x++; - if(x >= 160) - break; - bx >>= 1; } - bx = 128; + // do the window display + // LCDC.0 also enables/disables the window in !gbCgbMode ?!?! + // (tested on real hardware) + // This fixes Last Bible II & Zankurou Musouken + if ((register_LCDC & 0x01 || gbCgbMode) && (register_LCDC & 0x20) && (layerSettings & 0x2000) && (gbWindowLine != -2)) { + int i = 0; + // Fix (accurate emulation) for most of the window display problems + // (ie. Zen - Intergalactic Ninja, Urusei Yatsura...). + if ((gbWindowLine == -1) || (gbWindowLine > 144)) { + inUseRegister_WY = oldRegister_WY; + if (register_LY > oldRegister_WY) + gbWindowLine = 146; + // for (i = 0; i<160; i++) + // gbWindowColor[i] = gbLineMix[i]; + } - SpritesTicks = gbSpritesTicks[x]*(gbSpeed ? 2 : 4); + int wy = inUseRegister_WY; - sx = gbSCXLine[x+(gbSpeed ? 0 : 4)+SpritesTicks]; + if (y >= inUseRegister_WY) { - sy = gbSCYLine[x+(gbSpeed ? 11 : 5)+SpritesTicks]; + if ((gbWindowLine == -1) || (gbWindowLine > 144)) + gbWindowLine = 0; + int wx = register_WX; + int swx = 0; + wx -= 7; - tx = ((sx+x)>>3) & 0x1f; + if (wx <= 159 && gbWindowLine <= 143) { - sy+=y; + tile_map = 0x1800; - sy &= 255; + if ((register_LCDC & 0x40) != 0) + tile_map = 0x1c00; - ty = sy >> 3; + tx = 0; + ty = gbWindowLine >> 3; - by = sy & 7; + bx = 128; + by = gbWindowLine & 7; - tile_pattern_address = tile_pattern + tile * 16 + by * 2; + // Tries to emulate the 'window scrolling bug' when wx == 0 (ie. wx-7 == -7). + // Nothing close to perfect, but good enought for now... + if (wx == -7) { + swx = 7 - ((gbSCXLine[0] - 1) & 7); + bx >>= ((gbSCXLine[0] + ((swx != 1) ? 1 : 0)) & 7); + if (swx == 1) + swx = 2; - tile_map_line_y = tile_map + ty * 32; + //bx >>= ((gbSCXLine[0]+(((swx>1) && (swx != 7)) ? 1 : 0)) & 7); - tile_map_address = tile_map_line_y + tx; + if (swx == 7) { + //wx = 0; + if ((gbWindowLine > 0) || (wy == 0)) + swx = 0; + } + } else if (wx < 0) { + bx >>= (-wx); + wx = 0; + } - if(bank1) - attrs = bank1[tile_map_line_y + tx]; + tile_map_line_y = tile_map + ty * 32; - tile = bank0[tile_map_line_y + tx]; + tile_map_address = tile_map_line_y + tx; - if(!(register_LCDC & 0x10)) - tile ^= 0x80; + x = wx; - tile_pattern_address = tile_pattern + tile * 16 + by * 2; - } + 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; + + if (wx) + for (i = 0; i < swx; i++) + gbLineMix[i] = gbWindowColor[i]; + + 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 (x >= 0) { + if (attrs & 0x80) + gbLineBuffer[x] = 0x300 + c; + else + gbLineBuffer[x] = 0x100 + c; + + if (gbCgbMode) { + // Use the DMG palette if we are in compat mode. + if (gbMemory[0xff6c] & 1) { + c = gbBgp[c]; + } else { + c = c + (attrs & 7) * 4; + } + } else { + c = (gbBgpLine[x + (gbSpeed ? 5 : 11) + gbSpritesTicks[x] * (gbSpeed ? 2 : 4)] >> (c << 1)) & 3; + 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] & 0x7FFF] : gbPalette[c] & 0x7FFF; + } + 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; + } + + //for (i = swx; i<160; i++) + // gbLineMix[i] = gbWindowColor[i]; + gbWindowLine++; + } + } + } else if (gbWindowLine == -2) { + inUseRegister_WY = oldRegister_WY; + if (register_LY > oldRegister_WY) + gbWindowLine = 146; + else + gbWindowLine = 0; + } } else { - // Use gbBgp[0] instead of 0 (?) - // (this fixes white flashes on Last Bible II) - // Also added the gbColorOption (fixes Dracula Densetsu II color problems) - for(int i = 0; i < 160; i++) - { u16 color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; if (!gbCgbMode) - color = gbColorOption ? - gbColorFilter[gbPalette[gbBgpLine[i+(gbSpeed ? 5 : 11)+gbSpritesTicks[i]*(gbSpeed ? 2 : 4)]&3] & 0x7FFF] : - gbPalette[gbBgpLine[i+(gbSpeed ? 5 : 11)+gbSpritesTicks[i]*(gbSpeed ? 2 : 4)]&3] & 0x7FFF; - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - } - - // do the window display - // LCDC.0 also enables/disables the window in !gbCgbMode ?!?! - // (tested on real hardware) - // This fixes Last Bible II & Zankurou Musouken - if((register_LCDC & 0x01 || gbCgbMode) && (register_LCDC & 0x20) && (layerSettings & 0x2000) && (gbWindowLine != -2)) { - int i = 0; - // Fix (accurate emulation) for most of the window display problems - // (ie. Zen - Intergalactic Ninja, Urusei Yatsura...). - if ((gbWindowLine == -1) || (gbWindowLine>144)) - { - inUseRegister_WY = oldRegister_WY; - if (register_LY>oldRegister_WY) - gbWindowLine = 146; - // for (i = 0; i<160; i++) - // gbWindowColor[i] = gbLineMix[i]; - } - - int wy = inUseRegister_WY; - - if(y >= inUseRegister_WY) { - - if ((gbWindowLine == -1) || (gbWindowLine>144)) - gbWindowLine = 0; - - int wx = register_WX; - int swx = 0; - wx -= 7; - - if( wx <= 159 && gbWindowLine <= 143) { - - tile_map = 0x1800; - - if((register_LCDC & 0x40) != 0) - tile_map = 0x1c00; - - - tx = 0; - ty = gbWindowLine >> 3; - - bx = 128; - by = gbWindowLine & 7; - - // Tries to emulate the 'window scrolling bug' when wx == 0 (ie. wx-7 == -7). - // Nothing close to perfect, but good enought for now... - if (wx == -7) - { - swx = 7-((gbSCXLine[0]-1) & 7); - bx >>= ((gbSCXLine[0]+((swx != 1) ? 1 : 0)) & 7); - if (swx == 1) - swx = 2; - - //bx >>= ((gbSCXLine[0]+(((swx>1) && (swx != 7)) ? 1 : 0)) & 7); - - if (swx == 7) - { - //wx = 0; - if ((gbWindowLine>0) || (wy == 0)) - swx = 0; - } - } - else - 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; - - if (wx) - for (i = 0; i 0) { - u8 c = (tile_a & bx) != 0 ? 1 : 0; - c += ((tile_b & bx) != 0 ? 2 : 0); - - if (x>=0) - { - if(attrs & 0x80) - gbLineBuffer[x] = 0x300 + c; - else - gbLineBuffer[x] = 0x100 + c; - - if(gbCgbMode) { - // Use the DMG palette if we are in compat mode. - if (gbMemory[0xff6c] & 1) { - c = gbBgp[c]; - } else { - c = c + (attrs & 7) * 4; - } - } else { - c = (gbBgpLine[x+(gbSpeed ? 5 : 11)+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(c<<1)) &3; - 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] & 0x7FFF] : gbPalette[c] & 0x7FFF; - } - 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; - } - - //for (i = swx; i<160; i++) - // gbLineMix[i] = gbWindowColor[i]; - gbWindowLine++; + color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF; + for (int i = 0; i < 160; i++) { + gbLineMix[i] = color; + gbLineBuffer[i] = 0; } - } } - else if (gbWindowLine == -2) - { - inUseRegister_WY = oldRegister_WY; - if (register_LY>oldRegister_WY) - gbWindowLine = 146; - else - gbWindowLine = 0; - } - } else { - u16 color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF; - if (!gbCgbMode) - color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF; - for(int i = 0; i < 160; i++) - { - gbLineMix[i] = color; - gbLineBuffer[i] = 0; - } - } } -void gbDrawSpriteTile(int tile, int x,int y,int t, int flags, - int size,int spriteNumber) +void gbDrawSpriteTile(int tile, int x, int y, int t, int flags, + int size, int spriteNumber) { - u8 * bank0; - u8 * bank1; - if(gbCgbMode) { - bank0 = &gbVram[0x0000]; - bank1 = &gbVram[0x2000]; - } else { - bank0 = &gbMemory[0x8000]; - bank1 = NULL; - } - - int init = 0x0000; - - for (int i = 0; i<4; i++) - { - gbObp0[i] = (gbObp0Line[x+11+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(i<<1)) & 3; - gbObp1[i] = (gbObp1Line[x+11+gbSpritesTicks[x]*(gbSpeed ? 2 : 4)]>>(i<<1)) & 3; - } - 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]; - - // Fixes OAM-BG priority - if(prio && (register_LCDC & 1)) { - if(color < 0x200 && ((color & 0xFF) != 0)) - continue; - } - // Fixes OAM-BG priority for Moorhuhn 2 - if(color >= 0x300 && color != 0x300 && (register_LCDC & 1)) - 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 { - // Fixes GB sprites priorities (was '< x + 8' before) - // ('A boy and his blob...' sprites' emulation is now correct) - if(spriteX < x) - continue; - } - } - } - - - gbLineBuffer[xxx] = 0x200 + spriteNumber; - - // make sure that sprites will work even in CGB mode - if(gbCgbMode) { - // Use the DMG palette if we are in compat mode. - if (gbMemory[0xff6c] & 1) { - c = pal[c] + ((flags & 0x10) >> 4)*4 + 32; - } else { - c = c + (flags & 0x07)*4 + 32; - } + u8* bank0; + u8* bank1; + if (gbCgbMode) { + bank0 = &gbVram[0x0000]; + bank1 = &gbVram[0x2000]; } 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; - } + bank0 = &gbMemory[0x8000]; + bank1 = NULL; } - gbLineMix[xxx] = gbColorOption ? gbColorFilter[gbPalette[c] & 0x7FFF] : gbPalette[c] & 0x7FFF; - } + int init = 0x0000; + + for (int i = 0; i < 4; i++) { + gbObp0[i] = (gbObp0Line[x + 11 + gbSpritesTicks[x] * (gbSpeed ? 2 : 4)] >> (i << 1)) & 3; + gbObp1[i] = (gbObp1Line[x + 11 + gbSpritesTicks[x] * (gbSpeed ? 2 : 4)] >> (i << 1)) & 3; + } + 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]; + + // Fixes OAM-BG priority + if (prio && (register_LCDC & 1)) { + if (color < 0x200 && ((color & 0xFF) != 0)) + continue; + } + // Fixes OAM-BG priority for Moorhuhn 2 + if (color >= 0x300 && color != 0x300 && (register_LCDC & 1)) + 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 { + // Fixes GB sprites priorities (was '< x + 8' before) + // ('A boy and his blob...' sprites' emulation is now correct) + if (spriteX < x) + continue; + } + } + } + + gbLineBuffer[xxx] = 0x200 + spriteNumber; + + // make sure that sprites will work even in CGB mode + if (gbCgbMode) { + // Use the DMG palette if we are in compat mode. + if (gbMemory[0xff6c] & 1) { + c = pal[c] + ((flags & 0x10) >> 4) * 4 + 32; + } else { + 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] & 0x7FFF] : gbPalette[c] & 0x7FFF; + } } void gbDrawSprites(bool draw) { - int x = 0; - int y = 0; - int count = 0; + int x = 0; + int y = 0; + int count = 0; - int size = (register_LCDC & 4); + int size = (register_LCDC & 4); - if (!draw) - memset (gbSpritesTicks, 0, sizeof(gbSpritesTicks)); + if (!draw) + memset(gbSpritesTicks, 0, sizeof(gbSpritesTicks)); - if(!(register_LCDC & 0x80)) - return; + if (!(register_LCDC & 0x80)) + return; - if((register_LCDC & 2) && (layerSettings & 0x1000)) { - int yc = register_LY; + 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++]; + 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) || (!size && t >= 0 && t < 8)) { - if (draw) - gbDrawSpriteTile(tile,x-8,yc,t,flags,size,i); - else - { - for (int j = x-8; j<300; j++) - if (j>=0) - { - if (gbSpeed) - gbSpritesTicks[j] += 5; - else - gbSpritesTicks[j] += 2+(count&1); - } - } - count++; + 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) || (!size && t >= 0 && t < 8)) { + if (draw) + gbDrawSpriteTile(tile, x - 8, yc, t, flags, size, i); + else { + for (int j = x - 8; j < 300; j++) + if (j >= 0) { + if (gbSpeed) + gbSpritesTicks[j] += 5; + else + gbSpritesTicks[j] += 2 + (count & 1); + } + } + count++; + } + } + // sprite limit reached! + if (count >= 10) + break; } - } - // sprite limit reached! - if(count >= 10) - break; } - } - return; + return; } diff --git a/src/gb/gbGlobals.cpp b/src/gb/gbGlobals.cpp index 4977853f..53a55501 100644 --- a/src/gb/gbGlobals.cpp +++ b/src/gb/gbGlobals.cpp @@ -1,7 +1,7 @@ -#include #include "../common/Types.h" +#include -u8 *gbMemoryMap[16]; +u8* gbMemoryMap[16]; int gbRomSizeMask = 0; int gbRomSize = 0; @@ -9,18 +9,18 @@ int gbRamSizeMask = 0; int gbRamSize = 0; int gbTAMA5ramSize = 0; -u8 *gbMemory = NULL; -u8 *gbVram = NULL; -u8 *gbRom = NULL; -u8 *gbRam = NULL; -u8 *gbWram = NULL; -u16 *gbLineBuffer = NULL; -u8 *gbTAMA5ram = NULL; +u8* gbMemory = NULL; +u8* gbVram = NULL; +u8* gbRom = NULL; +u8* gbRam = NULL; +u8* gbWram = NULL; +u16* gbLineBuffer = NULL; +u8* gbTAMA5ram = 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}; +u8 gbBgp[4] = { 0, 1, 2, 3 }; +u8 gbObp0[4] = { 0, 1, 2, 3 }; +u8 gbObp1[4] = { 0, 1, 2, 3 }; int gbWindowLine = -1; bool genericflashcardEnable = false; diff --git a/src/gb/gbGlobals.h b/src/gb/gbGlobals.h index 1fafb75a..e7fe1b16 100644 --- a/src/gb/gbGlobals.h +++ b/src/gb/gbGlobals.h @@ -7,17 +7,17 @@ extern int gbRamSize; extern int gbRamSizeMask; extern int gbTAMA5ramSize; -extern u8 *bios; +extern u8* bios; -extern u8 *gbRom; -extern u8 *gbRam; -extern u8 *gbVram; -extern u8 *gbWram; -extern u8 *gbMemory; -extern u16 *gbLineBuffer; -extern u8 *gbTAMA5ram; +extern u8* gbRom; +extern u8* gbRam; +extern u8* gbVram; +extern u8* gbWram; +extern u8* gbMemory; +extern u16* gbLineBuffer; +extern u8* gbTAMA5ram; -extern u8 *gbMemoryMap[16]; +extern u8* gbMemoryMap[16]; extern int gbFrameSkip; extern u16 gbColorFilter[32768]; diff --git a/src/gb/gbMemory.cpp b/src/gb/gbMemory.cpp index 53a7f69e..87ebc1cb 100644 --- a/src/gb/gbMemory.cpp +++ b/src/gb/gbMemory.cpp @@ -1,1703 +1,1617 @@ +#include "gbMemory.h" #include "../System.h" #include "../common/Port.h" -#include "gbGlobals.h" -#include "gbMemory.h" #include "gb.h" -u8 gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -const u8 gbDisabledRam [8] = {0x80, 0xff, 0xf0, 0x00, 0x30, 0xbf, 0xbf, 0xbf}; +#include "gbGlobals.h" +u8 gbDaysinMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +const u8 gbDisabledRam[8] = { 0x80, 0xff, 0xf0, 0x00, 0x30, 0xbf, 0xbf, 0xbf }; extern int gbGBCColorType; extern gbRegister PC; mapperMBC1 gbDataMBC1 = { - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // memory model - 0, // ROM high address - 0, // RAM address - 0 // Rom Bank 0 remapping + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // memory model + 0, // ROM high address + 0, // RAM address + 0 // Rom Bank 0 remapping }; // MBC1 ROM write registers void mapperMBC1ROM(u16 address, u8 value) { - int tmpAddress = 0; + 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 == 1) && (address == 0x2100)) - gbDataMBC1.mapperRomBank0Remapping = 1; - - if((value & 0x1f) == 0) - value += 1; - if(value == gbDataMBC1.mapperROMBank) - break; - - tmpAddress = value << 14; - - // check current model - if (gbDataMBC1.mapperRomBank0Remapping == 3) { - tmpAddress = (value & 0xf) << 14; - tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 18; - } - else - if(gbDataMBC1.mapperMemoryModel == 0) { - // model is 16/8, so we have a high address in use - tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 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) { - if (!gbRamSize) - { - if (gbDataMBC1.mapperRomBank0Remapping == 3) - { - gbDataMBC1.mapperROMHighAddress = value & 0x03; - tmpAddress = (gbDataMBC1.mapperROMHighAddress) << 18; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x00] = &gbRom[tmpAddress]; - gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; - gbMemoryMap[0x04] = &gbRom[tmpAddress + 0x4000]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x5000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x6000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x7000]; - } - else gbDataMBC1.mapperRomBank0Remapping = 0; - } - // 4/32 model, RAM bank switching provided - value = value & 0x03; - if(value == gbDataMBC1.mapperRAMBank) + switch (address & 0x6000) { + case 0x0000: // RAM enable register + gbDataMBC1.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); break; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - } - gbDataMBC1.mapperRAMBank = value; - gbDataMBC1.mapperRAMAddress = tmpAddress; + case 0x2000: // ROM bank select + // value = value & 0x1f; + if ((value == 1) && (address == 0x2100)) + gbDataMBC1.mapperRomBank0Remapping = 1; - if (gbDataMBC1.mapperRomBank0Remapping != 3) - gbDataMBC1.mapperROMHighAddress = 0; - } 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]; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[0]; - gbMemoryMap[0x0b] = &gbRam[0x1000]; - } + if ((value & 0x1f) == 0) + value += 1; + if (value == gbDataMBC1.mapperROMBank) + break; - gbDataMBC1.mapperRAMBank = 0; + tmpAddress = value << 14; + + // check current model + if (gbDataMBC1.mapperRomBank0Remapping == 3) { + tmpAddress = (value & 0xf) << 14; + tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 18; + } else if (gbDataMBC1.mapperMemoryModel == 0) { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 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) { + if (!gbRamSize) { + if (gbDataMBC1.mapperRomBank0Remapping == 3) { + gbDataMBC1.mapperROMHighAddress = value & 0x03; + tmpAddress = (gbDataMBC1.mapperROMHighAddress) << 18; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x00] = &gbRom[tmpAddress]; + gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + gbMemoryMap[0x04] = &gbRom[tmpAddress + 0x4000]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x5000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x6000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x7000]; + } else + gbDataMBC1.mapperRomBank0Remapping = 0; + } + // 4/32 model, RAM bank switching provided + value = value & 0x03; + if (value == gbDataMBC1.mapperRAMBank) + break; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + if (gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } + gbDataMBC1.mapperRAMBank = value; + gbDataMBC1.mapperRAMAddress = tmpAddress; + + if (gbDataMBC1.mapperRomBank0Remapping != 3) + gbDataMBC1.mapperROMHighAddress = 0; + } 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]; + if (gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[0]; + gbMemoryMap[0x0b] = &gbRam[0x1000]; + } + + gbDataMBC1.mapperRAMBank = 0; + } + break; + case 0x6000: // memory model select + gbDataMBC1.mapperMemoryModel = value & 1; + + if (gbDataMBC1.mapperMemoryModel == 1) { + // 4/32 model, RAM bank switching provided + + value = gbDataMBC1.mapperRAMBank & 0x03; + tmpAddress = value << 13; + tmpAddress &= gbRamSizeMask; + if (gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; + gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; + gbDataMBC1.mapperRomBank0Remapping = 0; + } else + gbDataMBC1.mapperRomBank0Remapping |= 2; + + gbDataMBC1.mapperRAMBank = value; + gbDataMBC1.mapperRAMAddress = tmpAddress; + + tmpAddress = gbDataMBC1.mapperROMBank << 14; + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + } else { + // 16/8, set the high address + + 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]; + if (gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[0]; + gbMemoryMap[0x0b] = &gbRam[0x1000]; + } + } + break; } - break; - case 0x6000: // memory model select - gbDataMBC1.mapperMemoryModel = value & 1; - - if(gbDataMBC1.mapperMemoryModel == 1) { - // 4/32 model, RAM bank switching provided - - value = gbDataMBC1.mapperRAMBank & 0x03; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; - gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; - gbDataMBC1.mapperRomBank0Remapping = 0; - } - else gbDataMBC1.mapperRomBank0Remapping |=2; - - gbDataMBC1.mapperRAMBank = value; - gbDataMBC1.mapperRAMAddress = tmpAddress; - - tmpAddress = gbDataMBC1.mapperROMBank << 14; - - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - } else { - // 16/8, set the high address - - 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]; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[0]; - gbMemoryMap[0x0b] = &gbRam[0x1000]; - } - } - break; - } } // MBC1 RAM write void mapperMBC1RAM(u16 address, u8 value) { - if(gbDataMBC1.mapperRAMEnable) { - if(gbRamSize) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + if (gbDataMBC1.mapperRAMEnable) { + if (gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } } - } } // MBC1 read RAM u8 mapperMBC1ReadRAM(u16 address) { - if(gbDataMBC1.mapperRAMEnable) - return gbMemoryMap[address>>12][address & 0x0fff]; + if (gbDataMBC1.mapperRAMEnable) + return gbMemoryMap[address >> 12][address & 0x0fff]; - if (!genericflashcardEnable) - return 0xff; - else - if ((address & 0x1000) >= 0x1000) - { - // The value returned when reading RAM while it's disabled - // is constant, exept for the GBASP hardware. - // (actually, is the address that read is out of the ROM, the returned value if 0xff...) - if (PC.W>=0xff80) - return 0xff; - else - if ((gbHardware & 0x08) && (gbGBCColorType == 2)) - { - if (address & 1) - return 0xfb; - else - return 0x7a; - } - else - return 0x0a; - } - else - return gbDisabledRam[address & 7]; + if (!genericflashcardEnable) + return 0xff; + else if ((address & 0x1000) >= 0x1000) { + // The value returned when reading RAM while it's disabled + // is constant, exept for the GBASP hardware. + // (actually, is the address that read is out of the ROM, the returned value if 0xff...) + if (PC.W >= 0xff80) + return 0xff; + else if ((gbHardware & 0x08) && (gbGBCColorType == 2)) { + if (address & 1) + return 0xfb; + else + return 0x7a; + } else + return 0x0a; + } else + return gbDisabledRam[address & 7]; } void memoryUpdateMapMBC1() { - int tmpAddress = gbDataMBC1.mapperROMBank << 14; + int tmpAddress = gbDataMBC1.mapperROMBank << 14; - // check current model - if (gbDataMBC1.mapperRomBank0Remapping == 3) { - tmpAddress = (gbDataMBC1.mapperROMHighAddress & 3) << 18; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x00] = &gbRom[tmpAddress]; - gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + // check current model + if (gbDataMBC1.mapperRomBank0Remapping == 3) { + tmpAddress = (gbDataMBC1.mapperROMHighAddress & 3) << 18; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x00] = &gbRom[tmpAddress]; + gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; - tmpAddress |= (gbDataMBC1.mapperROMBank & 0xf) << 14; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - } - else - { - if(gbDataMBC1.mapperMemoryModel == 0) { - // model is 16/8, so we have a high address in use - tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 19; - } - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - } - - if(gbRamSize) { - if(gbDataMBC1.mapperMemoryModel == 1) { - gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; - gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; + tmpAddress |= (gbDataMBC1.mapperROMBank & 0xf) << 14; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; } else { - gbMemoryMap[0x0a] = &gbRam[0]; - gbMemoryMap[0x0b] = &gbRam[0x1000]; + if (gbDataMBC1.mapperMemoryModel == 0) { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMBC1.mapperROMHighAddress & 3) << 19; + } + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + } + + if (gbRamSize) { + if (gbDataMBC1.mapperMemoryModel == 1) { + gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; + gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; + } else { + gbMemoryMap[0x0a] = &gbRam[0]; + gbMemoryMap[0x0b] = &gbRam[0x1000]; + } } - } } mapperMBC2 gbDataMBC2 = { - 0, // RAM enable - 1 // ROM bank + 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; + 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; } - 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) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + if (gbDataMBC2.mapperRAMEnable) { + if (gbRamSize && address < 0xa200) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } } - } } void memoryUpdateMapMBC2() { - int tmpAddress = gbDataMBC2.mapperROMBank << 14; + int tmpAddress = gbDataMBC2.mapperROMBank << 14; - tmpAddress &= gbRomSizeMask; + tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + 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 + 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 = 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++; + time_t 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 > 59) { + gbDataMBC3.mapperMinutes -= 60; + gbDataMBC3.mapperHours++; + } + + diff /= 60; + + gbDataMBC3.mapperHours += (int)(diff % 24); + if (gbDataMBC3.mapperHours > 23) { + gbDataMBC3.mapperHours -= 24; + gbDataMBC3.mapperDays++; + } + diff /= 24; + + gbDataMBC3.mapperDays += (int)(diff & 0xffffffff); + if (gbDataMBC3.mapperDays > 255) { + if (gbDataMBC3.mapperDays > 511) { + gbDataMBC3.mapperDays %= 512; + gbDataMBC3.mapperControl |= 0x80; + } + gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | (gbDataMBC3.mapperDays > 255 ? 1 : 0); + } } - - diff /= 60; - - gbDataMBC3.mapperMinutes += (int)(diff % 60); - if(gbDataMBC3.mapperMinutes > 59) { - gbDataMBC3.mapperMinutes -= 60; - gbDataMBC3.mapperHours++; - } - - diff /= 60; - - gbDataMBC3.mapperHours += (int)(diff % 24); - if(gbDataMBC3.mapperHours > 23) { - gbDataMBC3.mapperHours -= 24; - gbDataMBC3.mapperDays++; - } - diff /= 24; - - gbDataMBC3.mapperDays += (int)(diff & 0xffffffff); - 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; + gbDataMBC3.mapperLastTime = now; } // MBC3 ROM write registers void mapperMBC3ROM(u16 address, u8 value) { - int tmpAddress = 0; + 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) + switch (address & 0x6000) { + case 0x0000: // RAM enable register + gbDataMBC3.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); 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; + case 0x2000: // ROM bank select + value = value & 0x7f; + if (value == 0) + value = 1; + if (value == gbDataMBC3.mapperROMBank) + break; - gbDataMBC3.mapperClockRegister = value; - } + 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; } - 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) { - gbMemoryMap[address>>12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } else { - time(&gbDataMBC3.mapperLastTime); - 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; - } + if (gbDataMBC3.mapperRAMEnable) { + if (gbDataMBC3.mapperRAMBank != -1) { + if (gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } else { + time(&gbDataMBC3.mapperLastTime); + 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 gbMemoryMap[address>>12][address & 0x0fff]; + if (gbDataMBC3.mapperRAMEnable) { + if (gbDataMBC3.mapperRAMBank != -1) { + return gbMemoryMap[address >> 12][address & 0x0fff]; + } + + 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; + } } - 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; - } - } - - if (!genericflashcardEnable) - return 0xff; - else - if ((address & 0x1000) >= 0x1000) - { - // The value returned when reading RAM while it's disabled - // is constant, exept for the GBASP hardware. - // (actually, is the address that read is out of the ROM, the returned value if 0xff...) - if (PC.W>=0xff80) - return 0xff; - else - if ((gbHardware & 0x08) && (gbGBCColorType == 2)) - { - if (address & 1) - return 0xfb; - else - return 0x7a; - } - else - return 0x0a; - } - else - return gbDisabledRam[address & 7]; + if (!genericflashcardEnable) + return 0xff; + else if ((address & 0x1000) >= 0x1000) { + // The value returned when reading RAM while it's disabled + // is constant, exept for the GBASP hardware. + // (actually, is the address that read is out of the ROM, the returned value if 0xff...) + if (PC.W >= 0xff80) + return 0xff; + else if ((gbHardware & 0x08) && (gbGBCColorType == 2)) { + if (address & 1) + return 0xfb; + else + return 0x7a; + } else + return 0x0a; + } else + return gbDisabledRam[address & 7]; } void memoryUpdateMapMBC3() { - int tmpAddress = gbDataMBC3.mapperROMBank << 14; + int tmpAddress = gbDataMBC3.mapperROMBank << 14; - tmpAddress &= gbRomSizeMask; + tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + 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]; - } + 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? + 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; + 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) + switch (address & 0x6000) { + case 0x0000: // RAM enable register + gbDataMBC5.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); break; + case 0x2000: // ROM bank select - tmpAddress = (value << 14) | (gbDataMBC5.mapperROMHighAddress << 22) ; + if (address < 0x3000) { + value = value & 0xff; + if (value == gbDataMBC5.mapperROMBank) + break; - tmpAddress &= gbRomSizeMask; - gbDataMBC5.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + tmpAddress = (value << 14) | (gbDataMBC5.mapperROMHighAddress << 22); - } else { - value = value & 1; - if(value == gbDataMBC5.mapperROMHighAddress) + 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]; - 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]; + gbDataMBC5.mapperRAMBank = value; + gbDataMBC5.mapperRAMAddress = tmpAddress; + } + break; } - 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) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + if (gbDataMBC5.mapperRAMEnable) { + if (gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } } - } } // MBC5 read RAM u8 mapperMBC5ReadRAM(u16 address) { - if(gbDataMBC5.mapperRAMEnable) - return gbMemoryMap[address>>12][address & 0x0fff]; + if (gbDataMBC5.mapperRAMEnable) + return gbMemoryMap[address >> 12][address & 0x0fff]; - if (!genericflashcardEnable) - return 0xff; - else - if ((address & 0x1000) >= 0x1000) - { - // The value returned when reading RAM while it's disabled - // is constant, exept for the GBASP hardware. - // (actually, is the address that read is out of the ROM, the returned value if 0xff...) - if (PC.W>=0xff80) - return 0xff; - else - if ((gbHardware & 0x08) && (gbGBCColorType == 2)) - { - if (address & 1) - return 0xfb; - else - return 0x7a; - } - else - return 0x0a; - } - else - return gbDisabledRam[address & 7]; + if (!genericflashcardEnable) + return 0xff; + else if ((address & 0x1000) >= 0x1000) { + // The value returned when reading RAM while it's disabled + // is constant, exept for the GBASP hardware. + // (actually, is the address that read is out of the ROM, the returned value if 0xff...) + if (PC.W >= 0xff80) + return 0xff; + else if ((gbHardware & 0x08) && (gbGBCColorType == 2)) { + if (address & 1) + return 0xfb; + else + return 0x7a; + } else + return 0x0a; + } else + return gbDisabledRam[address & 7]; } void memoryUpdateMapMBC5() { - int tmpAddress = (gbDataMBC5.mapperROMBank << 14) | - (gbDataMBC5.mapperROMHighAddress << 22) ; + 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]; + 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]; - } + 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 + 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; + int tmpAddress = 0; - switch(address & 0x6000) { - case 0x0000: - break; - case 0x2000: // ROM bank select - value = value & 0x7f; - if(value == 0) - value = 1; + switch (address & 0x6000) { + case 0x0000: + break; + case 0x2000: // ROM bank select + value = value & 0x7f; + if (value == 0) + value = 1; - if(value == gbDataMBC7.mapperROMBank) - break; + if (value == gbDataMBC7.mapperROMBank) + break; - tmpAddress = (value << 14); + 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]; + 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; + gbDataMBC7.mapperRAMBank = value; + gbDataMBC7.mapperRAMAddress = tmpAddress; + gbDataMBC7.mapperRAMEnable = 0; + } else { + gbDataMBC7.mapperRAMEnable = 0; + } + break; } - 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; - } - - if (!genericflashcardEnable) - return 0xff; - else - if ((address & 0x1000) >= 0x1000) - { - // The value returned when reading RAM while it's disabled - // is constant, exept for the GBASP hardware. - // (actually, is the address that read is out of the ROM, the returned value if 0xff...) - if (PC.W>=0xff80) - return 0xff; - else - if ((gbHardware & 0x08) && (gbGBCColorType == 2)) - { - if (address & 1) - return 0xfb; - else - return 0x7a; + 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; } - else - return 0x0a; - } - else - return gbDisabledRam[address & 7]; + + if (!genericflashcardEnable) + return 0xff; + else if ((address & 0x1000) >= 0x1000) { + // The value returned when reading RAM while it's disabled + // is constant, exept for the GBASP hardware. + // (actually, is the address that read is out of the ROM, the returned value if 0xff...) + if (PC.W >= 0xff80) + return 0xff; + else if ((gbHardware & 0x08) && (gbGBCColorType == 2)) { + if (address & 1) + return 0xfb; + else + return 0x7a; + } else + return 0x0a; + } else + return gbDisabledRam[address & 7]; } // MBC7 RAM write void mapperMBC7RAM(u16 address, u8 value) { - if(address == 0xa080) { - // special processing needed - int oldCs = gbDataMBC7.cs,oldSk=gbDataMBC7.sk; + if (address == 0xa080) { + // special processing needed + int oldCs = gbDataMBC7.cs, oldSk = gbDataMBC7.sk; - gbDataMBC7.cs=value>>7; - gbDataMBC7.sk=(value>>6)&1; + gbDataMBC7.cs = value >> 7; + gbDataMBC7.sk = (value >> 6) & 1; - if(!oldCs && gbDataMBC7.cs) { - if(gbDataMBC7.state==5) { - if(gbDataMBC7.writeEnable) { - gbMemory[0xa000+gbDataMBC7.address*2]=gbDataMBC7.buffer>>8; - gbMemory[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 (!oldCs && gbDataMBC7.cs) { + if (gbDataMBC7.state == 5) { if (gbDataMBC7.writeEnable) { - for(int i=0;i<256;i++) { - gbMemory[0xa000+i*2] = gbDataMBC7.buffer >> 8; - gbMemory[0xa000+i*2+1] = gbDataMBC7.buffer & 0xff; + gbMemory[0xa000 + gbDataMBC7.address * 2] = gbDataMBC7.buffer >> 8; + gbMemory[0xa000 + gbDataMBC7.address * 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; + gbDataMBC7.state = 0; + gbDataMBC7.value = 1; + } else { + gbDataMBC7.idle = true; + gbDataMBC7.state = 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 = (gbMemory[0xa000+gbDataMBC7.address*2]<<8)| - (gbMemory[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; + 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++) { + gbMemory[0xa000 + i * 2] = gbDataMBC7.buffer >> 8; + gbMemory[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 = (gbMemory[0xa000 + gbDataMBC7.address * 2] << 8) | (gbMemory[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 = (gbDataMBC7.mapperROMBank << 14); + int tmpAddress = (gbDataMBC7.mapperROMBank << 14); - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + 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 + 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; + 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) + 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; - 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) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + if (gbDataHuC1.mapperRAMEnable) { + if (gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = 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; + int tmpAddress = gbDataHuC1.mapperROMBank << 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; - } + + 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 gbMemoryMap[address >> 12][address & 0x0fff]; + if (gbDataHuC3.mapperRAMFlag > 0x0b && gbDataHuC3.mapperRAMFlag < 0x0e) { + if (gbDataHuC3.mapperRAMFlag != 0x0c) + return 1; + return gbDataHuC3.mapperRAMValue; + } else + return gbMemoryMap[address >> 12][address & 0x0fff]; } // HuC3 RAM write void mapperHuC3RAM(u16 address, u8 value) { - int *p; + int* p; - if(gbDataHuC3.mapperRAMFlag < 0x0b || - gbDataHuC3.mapperRAMFlag > 0x0e) { - if(gbDataHuC3.mapperRAMEnable) { - if(gbRamSize) { - gbMemoryMap[address >> 12][address & 0x0fff] = 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; + if (gbDataHuC3.mapperRAMFlag < 0x0b || gbDataHuC3.mapperRAMFlag > 0x0e) { + if (gbDataHuC3.mapperRAMEnable) { + if (gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = 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; + 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]; + 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]; - } + if (gbRamSize) { + tmpAddress = gbDataHuC3.mapperRAMBank << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } } // TAMA5 (for Tamagotchi 3 (gb)). // Very basic (and ugly :p) support, only rom bank switching is actually working... mapperTAMA5 gbDataTAMA5 = { - 1, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // RAM address - 0, // RAM Byte select - 0, // mapper command number - 0, // mapper last command; - { - 0, // commands 0x0 - 0, // commands 0x1 - 0, // commands 0x2 - 0, // commands 0x3 - 0, // commands 0x4 - 0, // commands 0x5 - 0, // commands 0x6 - 0, // commands 0x7 - 0, // commands 0x8 - 0, // commands 0x9 - 0, // commands 0xa - 0, // commands 0xb - 0, // commands 0xc - 0, // commands 0xd - 0, // commands 0xe - 0 // commands 0xf - }, - 0, // register - 0, // timer clock latch - 0, // timer clock register - 0, // timer seconds - 0, // timer minutes - 0, // timer hours - 0, // timer days - 0, // timer months - 0, // timer years - 0, // timer control - 0, // timer latched seconds - 0, // timer latched minutes - 0, // timer latched hours - 0, // timer latched days - 0, // timer latched months - 0, // timer latched years - 0, // timer latched control - (time_t)-1 // last time + 1, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // RAM address + 0, // RAM Byte select + 0, // mapper command number + 0, // mapper last command; + { + 0, // commands 0x0 + 0, // commands 0x1 + 0, // commands 0x2 + 0, // commands 0x3 + 0, // commands 0x4 + 0, // commands 0x5 + 0, // commands 0x6 + 0, // commands 0x7 + 0, // commands 0x8 + 0, // commands 0x9 + 0, // commands 0xa + 0, // commands 0xb + 0, // commands 0xc + 0, // commands 0xd + 0, // commands 0xe + 0 // commands 0xf + }, + 0, // register + 0, // timer clock latch + 0, // timer clock register + 0, // timer seconds + 0, // timer minutes + 0, // timer hours + 0, // timer days + 0, // timer months + 0, // timer years + 0, // timer control + 0, // timer latched seconds + 0, // timer latched minutes + 0, // timer latched hours + 0, // timer latched days + 0, // timer latched months + 0, // timer latched years + 0, // timer latched control + (time_t)-1 // last time }; - void memoryUpdateTAMA5Clock() { - if ((gbDataTAMA5.mapperYears & 3) == 0) - gbDaysinMonth[1] = 29; - else - gbDaysinMonth[1] = 28; + if ((gbDataTAMA5.mapperYears & 3) == 0) + gbDaysinMonth[1] = 29; + else + gbDaysinMonth[1] = 28; - time_t now = time(NULL); - time_t diff = now - gbDataTAMA5.mapperLastTime; - if(diff > 0) { - // update the clock according to the last update time - gbDataTAMA5.mapperSeconds += (int)(diff % 60); - if(gbDataTAMA5.mapperSeconds > 59) { - gbDataTAMA5.mapperSeconds -= 60; - gbDataTAMA5.mapperMinutes++; - } - - diff /= 60; - - gbDataTAMA5.mapperMinutes += (int)(diff % 60); - if(gbDataTAMA5.mapperMinutes > 59) { - gbDataTAMA5.mapperMinutes -= 60; - gbDataTAMA5.mapperHours++; - } - - diff /= 60; - - gbDataTAMA5.mapperHours += (int)(diff % 24); - diff /= 24; - if(gbDataTAMA5.mapperHours > 23) { - gbDataTAMA5.mapperHours -= 24; - diff++; - - } - - time_t days = diff; - while (days) - { - gbDataTAMA5.mapperDays++; - days--; - if (gbDataTAMA5.mapperDays>gbDaysinMonth[gbDataTAMA5.mapperMonths-1]) - { - gbDataTAMA5.mapperDays = 1; - gbDataTAMA5.mapperMonths++; - if (gbDataTAMA5.mapperMonths>12) - { - gbDataTAMA5.mapperMonths = 1; - gbDataTAMA5.mapperYears++; - if ((gbDataTAMA5.mapperYears & 3) == 0) - gbDaysinMonth[1] = 29; - else - gbDaysinMonth[1] = 28; + time_t now = time(NULL); + time_t diff = now - gbDataTAMA5.mapperLastTime; + if (diff > 0) { + // update the clock according to the last update time + gbDataTAMA5.mapperSeconds += (int)(diff % 60); + if (gbDataTAMA5.mapperSeconds > 59) { + gbDataTAMA5.mapperSeconds -= 60; + gbDataTAMA5.mapperMinutes++; + } + + diff /= 60; + + gbDataTAMA5.mapperMinutes += (int)(diff % 60); + if (gbDataTAMA5.mapperMinutes > 59) { + gbDataTAMA5.mapperMinutes -= 60; + gbDataTAMA5.mapperHours++; + } + + diff /= 60; + + gbDataTAMA5.mapperHours += (int)(diff % 24); + diff /= 24; + if (gbDataTAMA5.mapperHours > 23) { + gbDataTAMA5.mapperHours -= 24; + diff++; + } + + time_t days = diff; + while (days) { + gbDataTAMA5.mapperDays++; + days--; + if (gbDataTAMA5.mapperDays > gbDaysinMonth[gbDataTAMA5.mapperMonths - 1]) { + gbDataTAMA5.mapperDays = 1; + gbDataTAMA5.mapperMonths++; + if (gbDataTAMA5.mapperMonths > 12) { + gbDataTAMA5.mapperMonths = 1; + gbDataTAMA5.mapperYears++; + if ((gbDataTAMA5.mapperYears & 3) == 0) + gbDaysinMonth[1] = 29; + else + gbDaysinMonth[1] = 28; + } + } } - } } - } - gbDataTAMA5.mapperLastTime = now; - + gbDataTAMA5.mapperLastTime = now; } - - // TAMA5 RAM write void mapperTAMA5RAM(u16 address, u8 value) { - if ((address & 0xffff) <= 0xa001) - { - switch (address & 1) - { - case 0: // 'Values' Register - { - value &= 0xf; - gbDataTAMA5.mapperCommands[gbDataTAMA5.mapperCommandNumber] = value; - gbMemoryMap[0xa][0] = value; + if ((address & 0xffff) <= 0xa001) { + switch (address & 1) { + case 0: // 'Values' Register + { + value &= 0xf; + gbDataTAMA5.mapperCommands[gbDataTAMA5.mapperCommandNumber] = value; + gbMemoryMap[0xa][0] = value; -/* int test = gbDataTAMA5.mapperCommands[gbDataTAMA5.mapperCommandNumber & 0x0e] | + /* int test = gbDataTAMA5.mapperCommands[gbDataTAMA5.mapperCommandNumber & 0x0e] | (gbDataTAMA5.mapperCommands[(gbDataTAMA5.mapperCommandNumber & 0x0e) +1]<<4);*/ - if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 0) // Read Command !!! + if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 0) // Read Command !!! + { + gbDataTAMA5.mapperROMBank = gbDataTAMA5.mapperCommands[0] | (gbDataTAMA5.mapperCommands[1] << 4); + + int tmpAddress = (gbDataTAMA5.mapperROMBank << 14); + + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + gbDataTAMA5.mapperCommands[0x0f] = 0; + } else if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 4) { + gbDataTAMA5.mapperCommands[0x0f] = 1; + if (gbDataTAMA5.mapperCommandNumber == 4) + gbDataTAMA5.mapperCommands[5] = 0; // correct ? + } else if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 6) { + gbDataTAMA5.mapperRamByteSelect = (gbDataTAMA5.mapperCommands[7] << 4) | (gbDataTAMA5.mapperCommands[6] & 0x0f); + + // Write Commands !!! + if (gbDataTAMA5.mapperCommands[0x0f] && (gbDataTAMA5.mapperCommandNumber == 7)) { + int data = (gbDataTAMA5.mapperCommands[0x04] & 0x0f) | (gbDataTAMA5.mapperCommands[0x05] << 4); + + // Not sure when the write command should reset... + // but it doesn't seem to matter. + // gbDataTAMA5.mapperCommands[0x0f] = 0; + + if (gbDataTAMA5.mapperRamByteSelect == 0x8) // Timer stuff + { + switch (data & 0xf) { + case 0x7: + gbDataTAMA5.mapperDays = ((gbDataTAMA5.mapperDays) / 10) * 10 + (data >> 4); + break; + case 0x8: + gbDataTAMA5.mapperDays = (gbDataTAMA5.mapperDays % 10) + (data >> 4) * 10; + break; + case 0x9: + gbDataTAMA5.mapperMonths = ((gbDataTAMA5.mapperMonths) / 10) * 10 + (data >> 4); + break; + case 0xa: + gbDataTAMA5.mapperMonths = (gbDataTAMA5.mapperMonths % 10) + (data >> 4) * 10; + break; + case 0xb: + gbDataTAMA5.mapperYears = ((gbDataTAMA5.mapperYears) % 1000) + (data >> 4) * 1000; + break; + case 0xc: + gbDataTAMA5.mapperYears = (gbDataTAMA5.mapperYears % 100) + (gbDataTAMA5.mapperYears / 1000) * 1000 + (data >> 4) * 100; + break; + default: + break; + } + } else if (gbDataTAMA5.mapperRamByteSelect == 0x18) // Timer stuff again + { + memoryUpdateTAMA5Clock(); + gbDataTAMA5.mapperLSeconds = gbDataTAMA5.mapperSeconds; + gbDataTAMA5.mapperLMinutes = gbDataTAMA5.mapperMinutes; + gbDataTAMA5.mapperLHours = gbDataTAMA5.mapperHours; + gbDataTAMA5.mapperLDays = gbDataTAMA5.mapperDays; + gbDataTAMA5.mapperLMonths = gbDataTAMA5.mapperMonths; + gbDataTAMA5.mapperLYears = gbDataTAMA5.mapperYears; + gbDataTAMA5.mapperLControl = gbDataTAMA5.mapperControl; + + int seconds = (gbDataTAMA5.mapperLSeconds / 10) * 16 + gbDataTAMA5.mapperLSeconds % 10; + int secondsL = (gbDataTAMA5.mapperLSeconds % 10); + int secondsH = (gbDataTAMA5.mapperLSeconds / 10); + int minutes = (gbDataTAMA5.mapperLMinutes / 10) * 16 + gbDataTAMA5.mapperLMinutes % 10; + int hours = (gbDataTAMA5.mapperLHours / 10) * 16 + gbDataTAMA5.mapperLHours % 10; + int DaysL = gbDataTAMA5.mapperLDays % 10; + int DaysH = gbDataTAMA5.mapperLDays / 10; + int MonthsL = gbDataTAMA5.mapperLMonths % 10; + int MonthsH = gbDataTAMA5.mapperLMonths / 10; + int Years3 = (gbDataTAMA5.mapperLYears / 100) % 10; + int Years4 = (gbDataTAMA5.mapperLYears / 1000); + + switch (data & 0x0f) { + // I guess cases 0 and 1 are used for secondsL and secondsH + // so the game would update the timer values on screen when + // the seconds reset to 0... ? + case 0x0: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = secondsL; + break; + case 0x1: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = secondsH; + break; + case 0x7: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = DaysL; // days low + break; + case 0x8: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = DaysH; // days high + break; + case 0x9: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = MonthsL; // month low + break; + case 0xa: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = MonthsH; // month high + break; + case 0xb: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = Years4; // years 4th digit + break; + case 0xc: + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = Years3; // years 3rd digit + break; + default: + break; + } + + gbTAMA5ram[0x54] = seconds; // incorrect ? (not used by the game) ? + gbTAMA5ram[0x64] = minutes; + gbTAMA5ram[0x74] = hours; + gbTAMA5ram[0x84] = DaysH * 16 + DaysL; // incorrect ? (not used by the game) ? + gbTAMA5ram[0x94] = MonthsH * 16 + MonthsL; // incorrect ? (not used by the game) ? + + time(&gbDataTAMA5.mapperLastTime); + + gbMemoryMap[0xa][0] = 1; + } else if (gbDataTAMA5.mapperRamByteSelect == 0x28) // Timer stuff again + { + if ((data & 0xf) == 0xb) + gbDataTAMA5.mapperYears = ((gbDataTAMA5.mapperYears >> 2) << 2) + (data & 3); + } else if (gbDataTAMA5.mapperRamByteSelect == 0x44) { + gbDataTAMA5.mapperMinutes = (data / 16) * 10 + data % 16; + } else if (gbDataTAMA5.mapperRamByteSelect == 0x54) { + gbDataTAMA5.mapperHours = (data / 16) * 10 + data % 16; + } else { + gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = data; + } + } + } + } break; + case 1: // 'Commands' Register { - gbDataTAMA5.mapperROMBank = gbDataTAMA5.mapperCommands[0] | - (gbDataTAMA5.mapperCommands[1]<<4); + gbMemoryMap[0xa][1] = gbDataTAMA5.mapperCommandNumber = value; - int tmpAddress = (gbDataTAMA5.mapperROMBank << 14); - - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - - gbDataTAMA5.mapperCommands[0x0f] = 0; - } - else if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 4) - { - gbDataTAMA5.mapperCommands[0x0f] = 1; - if (gbDataTAMA5.mapperCommandNumber == 4) - gbDataTAMA5.mapperCommands[5] =0; // correct ? - } - else if ((gbDataTAMA5.mapperCommandNumber & 0xe) == 6) - { - gbDataTAMA5.mapperRamByteSelect = (gbDataTAMA5.mapperCommands[7]<<4) | - (gbDataTAMA5.mapperCommands[6]&0x0f); - - // Write Commands !!! - if (gbDataTAMA5.mapperCommands[0x0f] && (gbDataTAMA5.mapperCommandNumber == 7)) - { - int data = (gbDataTAMA5.mapperCommands[0x04] & 0x0f) | - (gbDataTAMA5.mapperCommands[0x05] <<4); - - // Not sure when the write command should reset... - // but it doesn't seem to matter. - // gbDataTAMA5.mapperCommands[0x0f] = 0; - - if (gbDataTAMA5.mapperRamByteSelect == 0x8) // Timer stuff - { - switch (data & 0xf) - { - case 0x7: - gbDataTAMA5.mapperDays = ((gbDataTAMA5.mapperDays)/10)*10 + (data >> 4); - break; - case 0x8: - gbDataTAMA5.mapperDays = (gbDataTAMA5.mapperDays%10) + (data >>4)*10; - break; - case 0x9: - gbDataTAMA5.mapperMonths = ((gbDataTAMA5.mapperMonths)/10)*10 + (data >> 4); - break; - case 0xa: - gbDataTAMA5.mapperMonths = (gbDataTAMA5.mapperMonths%10) + (data >>4)*10; - break; - case 0xb: - gbDataTAMA5.mapperYears = ((gbDataTAMA5.mapperYears)%1000) + (data >> 4)*1000; - break; - case 0xc: - gbDataTAMA5.mapperYears = (gbDataTAMA5.mapperYears%100) + (gbDataTAMA5.mapperYears/1000)*1000 + - (data >>4)*100; - break; - default : - break; - } - } - else if (gbDataTAMA5.mapperRamByteSelect == 0x18) // Timer stuff again - { - memoryUpdateTAMA5Clock(); - gbDataTAMA5.mapperLSeconds = gbDataTAMA5.mapperSeconds; - gbDataTAMA5.mapperLMinutes = gbDataTAMA5.mapperMinutes; - gbDataTAMA5.mapperLHours = gbDataTAMA5.mapperHours; - gbDataTAMA5.mapperLDays = gbDataTAMA5.mapperDays; - gbDataTAMA5.mapperLMonths = gbDataTAMA5.mapperMonths; - gbDataTAMA5.mapperLYears = gbDataTAMA5.mapperYears; - gbDataTAMA5.mapperLControl = gbDataTAMA5.mapperControl; - - int seconds = (gbDataTAMA5.mapperLSeconds / 10)*16 + gbDataTAMA5.mapperLSeconds %10; - int secondsL = (gbDataTAMA5.mapperLSeconds % 10); - int secondsH = (gbDataTAMA5.mapperLSeconds / 10); - int minutes = (gbDataTAMA5.mapperLMinutes / 10)*16 + gbDataTAMA5.mapperLMinutes %10; - int hours = (gbDataTAMA5.mapperLHours / 10)*16 + gbDataTAMA5.mapperLHours %10; - int DaysL = gbDataTAMA5.mapperLDays % 10; - int DaysH = gbDataTAMA5.mapperLDays /10; - int MonthsL = gbDataTAMA5.mapperLMonths % 10; - int MonthsH = gbDataTAMA5.mapperLMonths / 10; - int Years3 = (gbDataTAMA5.mapperLYears / 100) % 10; - int Years4 = (gbDataTAMA5.mapperLYears / 1000); - - switch (data & 0x0f) - { - // I guess cases 0 and 1 are used for secondsL and secondsH - // so the game would update the timer values on screen when - // the seconds reset to 0... ? - case 0x0: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = secondsL; - break; - case 0x1: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = secondsH; - break; - case 0x7: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = DaysL; // days low - break; - case 0x8: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = DaysH; // days high - break; - case 0x9: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = MonthsL; // month low - break; - case 0xa: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = MonthsH; // month high - break; - case 0xb: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = Years4; // years 4th digit - break; - case 0xc: - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = Years3; // years 3rd digit - break; - default : - break; - } - - gbTAMA5ram[0x54] = seconds; // incorrect ? (not used by the game) ? - gbTAMA5ram[0x64] = minutes; - gbTAMA5ram[0x74] = hours; - gbTAMA5ram[0x84] = DaysH*16+DaysL; // incorrect ? (not used by the game) ? - gbTAMA5ram[0x94] = MonthsH*16+MonthsL; // incorrect ? (not used by the game) ? - - time(&gbDataTAMA5.mapperLastTime); - - gbMemoryMap[0xa][0] = 1; - } - else if (gbDataTAMA5.mapperRamByteSelect == 0x28) // Timer stuff again - { - if ((data & 0xf) == 0xb) - gbDataTAMA5.mapperYears = ((gbDataTAMA5.mapperYears>>2)<<2) + (data & 3); - } - else if (gbDataTAMA5.mapperRamByteSelect == 0x44) - { - gbDataTAMA5.mapperMinutes = (data/16)*10 + data%16; - } - else if (gbDataTAMA5.mapperRamByteSelect == 0x54) - { - gbDataTAMA5.mapperHours = (data/16)*10 + data%16; - } - else - { - gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect] = data; - } - } - } - } - break; - case 1: // 'Commands' Register - { - gbMemoryMap[0xa][1] = gbDataTAMA5.mapperCommandNumber = value; - - // This should be only a 'is the flashrom ready ?' command. - // However as I couldn't find any 'copy' command - // (that seems to be needed for the saving system to work) - // I put it there... - if (value == 0x0a) - { - for (int i = 0; i<0x10; i++) - for (int j = 0; j<0x10; j++) - if (!(j&2)) - gbTAMA5ram[((i*0x10)+j) | 2] = gbTAMA5ram[(i*0x10)+j]; - // Enable this to see the content of the flashrom in 0xe000 - /*for (int k = 0; k<0x100; k++) + // This should be only a 'is the flashrom ready ?' command. + // However as I couldn't find any 'copy' command + // (that seems to be needed for the saving system to work) + // I put it there... + if (value == 0x0a) { + for (int i = 0; i < 0x10; i++) + for (int j = 0; j < 0x10; j++) + if (!(j & 2)) + gbTAMA5ram[((i * 0x10) + j) | 2] = gbTAMA5ram[(i * 0x10) + j]; + // Enable this to see the content of the flashrom in 0xe000 + /*for (int k = 0; k<0x100; k++) gbMemoryMap[0xe][k] = gbTAMA5ram[k];*/ - gbMemoryMap[0xa][0] = gbDataTAMA5.mapperRAMEnable = 1; + gbMemoryMap[0xa][0] = gbDataTAMA5.mapperRAMEnable = 1; + } else { + if ((value & 0x0e) == 0x0c) { + gbDataTAMA5.mapperRamByteSelect = gbDataTAMA5.mapperCommands[6] | (gbDataTAMA5.mapperCommands[7] << 4); + + u8 byte = gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect]; + + gbMemoryMap[0xa][0] = (value & 1) ? byte >> 4 : byte & 0x0f; + + gbDataTAMA5.mapperCommands[0x0f] = 0; + } + } + break; } - else - { - if ((value & 0x0e) == 0x0c) - { - gbDataTAMA5.mapperRamByteSelect = gbDataTAMA5.mapperCommands[6] | - (gbDataTAMA5.mapperCommands[7]<<4); - - u8 byte = gbTAMA5ram[gbDataTAMA5.mapperRamByteSelect]; - - gbMemoryMap[0xa][0] = (value & 1) ? byte >> 4 : byte & 0x0f; - - gbDataTAMA5.mapperCommands[0x0f] = 0; - } } - break; - } + } else { + if (gbDataTAMA5.mapperRAMEnable) { + if (gbDataTAMA5.mapperRAMBank != -1) { + if (gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } + } + } } - } - else - { - if(gbDataTAMA5.mapperRAMEnable) { - if(gbDataTAMA5.mapperRAMBank != -1) { - if(gbRamSize) { - gbMemoryMap[address>>12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - } - } - } } - // TAMA5 read RAM u8 mapperTAMA5ReadRAM(u16 address) { - return gbMemoryMap[address>>12][address & 0xfff]; + return gbMemoryMap[address >> 12][address & 0xfff]; } - void memoryUpdateMapTAMA5() { - int tmpAddress = (gbDataTAMA5.mapperROMBank << 14); + int tmpAddress = (gbDataTAMA5.mapperROMBank << 14); - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - if(gbRamSize) { - tmpAddress = 0 << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - } + if (gbRamSize) { + tmpAddress = 0 << 13; + tmpAddress &= gbRamSizeMask; + gbMemoryMap[0x0a] = &gbRam[tmpAddress]; + gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; + } } // MMM01 Used in Momotarou collection (however the rom is corrupted) -mapperMMM01 gbDataMMM01 ={ - 0, // RAM enable - 1, // ROM bank - 0, // RAM bank - 0, // memory model - 0, // ROM high address - 0, // RAM address - 0 // Rom Bank 0 remapping +mapperMMM01 gbDataMMM01 = { + 0, // RAM enable + 1, // ROM bank + 0, // RAM bank + 0, // memory model + 0, // ROM high address + 0, // RAM address + 0 // Rom Bank 0 remapping }; // MMM01 ROM write registers void mapperMMM01ROM(u16 address, u8 value) { - int tmpAddress = 0; + int tmpAddress = 0; - switch(address & 0x6000) { - case 0x0000: // RAM enable register - gbDataMMM01.mapperRAMEnable = ( ( value & 0x0a) == 0x0a ? 1 : 0); - break; - case 0x2000: // ROM bank select - // value = value & 0x1f; - if(value == 0) - value = 1; - if(value == gbDataMMM01.mapperROMBank) - break; - - tmpAddress = value << 14; - - // check current model - if(gbDataMMM01.mapperMemoryModel == 0) { - // model is 16/8, so we have a high address in use - tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; - } - else - tmpAddress |= gbDataMMM01.mapperRomBank0Remapping << 18; - - tmpAddress &= gbRomSizeMask; - gbDataMMM01.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(gbDataMMM01.mapperMemoryModel == 1) { - // 4/32 model, RAM bank switching provided - value = value & 0x03; - if(value == gbDataMBC1.mapperRAMBank) + switch (address & 0x6000) { + case 0x0000: // RAM enable register + gbDataMMM01.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); break; - tmpAddress = value << 13; - tmpAddress &= gbRamSizeMask; - gbMemoryMap[0x0a] = &gbRam[tmpAddress]; - gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; - gbDataMMM01.mapperRAMBank = value; - gbDataMMM01.mapperRAMAddress = tmpAddress; - } else { - // 16/8, set the high address - gbDataMMM01.mapperROMHighAddress = value & 0x03; - tmpAddress = gbDataMMM01.mapperROMBank << 14; - tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + case 0x2000: // ROM bank select + // value = value & 0x1f; + if (value == 0) + value = 1; + if (value == gbDataMMM01.mapperROMBank) + break; - gbDataMMM01.mapperRomBank0Remapping = ((value<<1) | (value & 0x40 ? 1 : 0)) & 0xff; - tmpAddress = gbDataMMM01.mapperRomBank0Remapping << 18; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x00] = &gbRom[tmpAddress]; - gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + tmpAddress = value << 14; + + // check current model + if (gbDataMMM01.mapperMemoryModel == 0) { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; + } else + tmpAddress |= gbDataMMM01.mapperRomBank0Remapping << 18; + + tmpAddress &= gbRomSizeMask; + gbDataMMM01.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 (gbDataMMM01.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]; + gbDataMMM01.mapperRAMBank = value; + gbDataMMM01.mapperRAMAddress = tmpAddress; + } else { + // 16/8, set the high address + gbDataMMM01.mapperROMHighAddress = value & 0x03; + tmpAddress = gbDataMMM01.mapperROMBank << 14; + tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + + gbDataMMM01.mapperRomBank0Remapping = ((value << 1) | (value & 0x40 ? 1 : 0)) & 0xff; + tmpAddress = gbDataMMM01.mapperRomBank0Remapping << 18; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x00] = &gbRom[tmpAddress]; + gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + } + break; + case 0x6000: // memory model select + gbDataMMM01.mapperMemoryModel = value & 1; + break; } - break; - case 0x6000: // memory model select - gbDataMMM01.mapperMemoryModel = value & 1; - break; - } } // MMM01 RAM write void mapperMMM01RAM(u16 address, u8 value) { - if(gbDataMMM01.mapperRAMEnable) { - if(gbRamSize) { - gbMemoryMap[address >> 12][address & 0x0fff] = value; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + if (gbDataMMM01.mapperRAMEnable) { + if (gbRamSize) { + gbMemoryMap[address >> 12][address & 0x0fff] = value; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } } - } } void memoryUpdateMapMMM01() { - int tmpAddress = gbDataMMM01.mapperROMBank << 14; + int tmpAddress = gbDataMMM01.mapperROMBank << 14; - // check current model - if(gbDataMMM01.mapperMemoryModel == 1) { - // model is 16/8, so we have a high address in use - tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; - } + // check current model + if (gbDataMMM01.mapperMemoryModel == 1) { + // model is 16/8, so we have a high address in use + tmpAddress |= (gbDataMMM01.mapperROMHighAddress) << 19; + } - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; - tmpAddress = gbDataMMM01.mapperRomBank0Remapping << 18; - tmpAddress &= gbRomSizeMask; - gbMemoryMap[0x00] = &gbRom[tmpAddress]; - gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; - gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; - gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; + tmpAddress = gbDataMMM01.mapperRomBank0Remapping << 18; + tmpAddress &= gbRomSizeMask; + gbMemoryMap[0x00] = &gbRom[tmpAddress]; + gbMemoryMap[0x01] = &gbRom[tmpAddress + 0x1000]; + gbMemoryMap[0x02] = &gbRom[tmpAddress + 0x2000]; + gbMemoryMap[0x03] = &gbRom[tmpAddress + 0x3000]; - if(gbRamSize) { - gbMemoryMap[0x0a] = &gbRam[gbDataMMM01.mapperRAMAddress]; - gbMemoryMap[0x0b] = &gbRam[gbDataMMM01.mapperRAMAddress + 0x1000]; - } + if (gbRamSize) { + gbMemoryMap[0x0a] = &gbRam[gbDataMMM01.mapperRAMAddress]; + gbMemoryMap[0x0b] = &gbRam[gbDataMMM01.mapperRAMAddress + 0x1000]; + } } // GameGenie ROM write registers void mapperGGROM(u16 address, u8 value) { - switch(address & 0x6000) { - case 0x0000: // RAM enable register - break; - case 0x2000: // GameGenie has only a half bank - break; - case 0x4000: // GameGenie has no RAM - if ((address >=0x4001) && (address <= 0x4020)) // GG Hardware Registers - gbMemoryMap[address >> 12][address & 0x0fff] = value; - break; - case 0x6000: // GameGenie has only a half bank - break; - } + switch (address & 0x6000) { + case 0x0000: // RAM enable register + break; + case 0x2000: // GameGenie has only a half bank + break; + case 0x4000: // GameGenie has no RAM + if ((address >= 0x4001) && (address <= 0x4020)) // GG Hardware Registers + gbMemoryMap[address >> 12][address & 0x0fff] = value; + break; + case 0x6000: // GameGenie has only a half bank + break; + } } - // GS3 Used to emulate the GS V3.0 rom bank switching mapperGS3 gbDataGS3 = { 1 }; // ROM bank void mapperGS3ROM(u16 address, u8 value) { - int tmpAddress = 0; + int tmpAddress = 0; - switch(address & 0x6000) { - case 0x0000: // GS has no ram - break; - case 0x2000: // GS has no 'classic' ROM bank select - break; - case 0x4000: // GS has no ram - break; - case 0x6000: // 0x6000 area is RW, and used for GS hardware registers - - if (address == 0x7FE1) // This is the (half) ROM bank select register - { - if(value == gbDataGS3.mapperROMBank) + switch (address & 0x6000) { + case 0x0000: // GS has no ram break; - tmpAddress = value << 13; + case 0x2000: // GS has no 'classic' ROM bank select + break; + case 0x4000: // GS has no ram + break; + case 0x6000: // 0x6000 area is RW, and used for GS hardware registers - tmpAddress &= gbRomSizeMask; - gbDataGS3.mapperROMBank = value; - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + if (address == 0x7FE1) // This is the (half) ROM bank select register + { + if (value == gbDataGS3.mapperROMBank) + break; + tmpAddress = value << 13; + + tmpAddress &= gbRomSizeMask; + gbDataGS3.mapperROMBank = value; + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + } else + gbMemoryMap[address >> 12][address & 0x0fff] = value; + break; } - else - gbMemoryMap[address>>12][address & 0x0fff] = value; - break; - } } void memoryUpdateMapGS3() { - int tmpAddress = gbDataGS3.mapperROMBank << 13; + int tmpAddress = gbDataGS3.mapperROMBank << 13; - tmpAddress &= gbRomSizeMask; - // GS can only change a half ROM bank - gbMemoryMap[0x04] = &gbRom[tmpAddress]; - gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; + tmpAddress &= gbRomSizeMask; + // GS can only change a half ROM bank + gbMemoryMap[0x04] = &gbRom[tmpAddress]; + gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; } diff --git a/src/gb/gbMemory.h b/src/gb/gbMemory.h index ad737e96..c2052456 100644 --- a/src/gb/gbMemory.h +++ b/src/gb/gbMemory.h @@ -4,134 +4,134 @@ #include struct mapperMBC1 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperMemoryModel; - int mapperROMHighAddress; - int mapperRAMAddress; - int mapperRomBank0Remapping; + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperMemoryModel; + int mapperROMHighAddress; + int mapperRAMAddress; + int mapperRomBank0Remapping; }; struct mapperMBC2 { - int mapperRAMEnable; - int mapperROMBank; + int mapperRAMEnable; + int mapperROMBank; }; struct mapperMBC3 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperRAMAddress; - int mapperClockLatch; - int mapperClockRegister; - int mapperSeconds; - int mapperMinutes; - int mapperHours; - int mapperDays; - int mapperControl; - int mapperLSeconds; - int mapperLMinutes; - int mapperLHours; - int mapperLDays; - int mapperLControl; - time_t mapperLastTime; + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperRAMAddress; + int mapperClockLatch; + int mapperClockRegister; + int mapperSeconds; + int mapperMinutes; + int mapperHours; + int mapperDays; + int mapperControl; + int mapperLSeconds; + int mapperLMinutes; + int mapperLHours; + int mapperLDays; + int mapperLControl; + time_t mapperLastTime; }; struct mapperMBC5 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperROMHighAddress; - int mapperRAMAddress; - int isRumbleCartridge; + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperROMHighAddress; + int mapperRAMAddress; + int isRumbleCartridge; }; struct mapperMBC7 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperRAMAddress; - int cs; - int sk; - int state; - int buffer; - int idle; - int count; - int code; - int address; - int writeEnable; - int value; + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperRAMAddress; + int cs; + int sk; + int state; + int buffer; + int idle; + int count; + int code; + int address; + int writeEnable; + int value; }; struct mapperHuC1 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperMemoryModel; - int mapperROMHighAddress; - int mapperRAMAddress; + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperMemoryModel; + int mapperROMHighAddress; + int mapperRAMAddress; }; struct mapperHuC3 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperRAMAddress; - int mapperAddress; - int mapperRAMFlag; - int mapperRAMValue; - int mapperRegister1; - int mapperRegister2; - int mapperRegister3; - int mapperRegister4; - int mapperRegister5; - int mapperRegister6; - int mapperRegister7; - int mapperRegister8; + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperRAMAddress; + int mapperAddress; + int mapperRAMFlag; + int mapperRAMValue; + int mapperRegister1; + int mapperRegister2; + int mapperRegister3; + int mapperRegister4; + int mapperRegister5; + int mapperRegister6; + int mapperRegister7; + int mapperRegister8; }; struct mapperTAMA5 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperRAMAddress; - int mapperRamByteSelect; - int mapperCommandNumber; - int mapperLastCommandNumber; - int mapperCommands[0x10]; - int mapperRegister; - int mapperClockLatch; - int mapperClockRegister; - int mapperSeconds; - int mapperMinutes; - int mapperHours; - int mapperDays; - int mapperMonths; - int mapperYears; - int mapperControl; - int mapperLSeconds; - int mapperLMinutes; - int mapperLHours; - int mapperLDays; - int mapperLMonths; - int mapperLYears; - int mapperLControl; - time_t mapperLastTime; + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperRAMAddress; + int mapperRamByteSelect; + int mapperCommandNumber; + int mapperLastCommandNumber; + int mapperCommands[0x10]; + int mapperRegister; + int mapperClockLatch; + int mapperClockRegister; + int mapperSeconds; + int mapperMinutes; + int mapperHours; + int mapperDays; + int mapperMonths; + int mapperYears; + int mapperControl; + int mapperLSeconds; + int mapperLMinutes; + int mapperLHours; + int mapperLDays; + int mapperLMonths; + int mapperLYears; + int mapperLControl; + time_t mapperLastTime; }; struct mapperMMM01 { - int mapperRAMEnable; - int mapperROMBank; - int mapperRAMBank; - int mapperMemoryModel; - int mapperROMHighAddress; - int mapperRAMAddress; - int mapperRomBank0Remapping; + int mapperRAMEnable; + int mapperROMBank; + int mapperRAMBank; + int mapperMemoryModel; + int mapperROMHighAddress; + int mapperRAMAddress; + int mapperRomBank0Remapping; }; struct mapperGS3 { - int mapperROMBank; + int mapperROMBank; }; extern mapperMBC1 gbDataMBC1; diff --git a/src/gb/gbPrinter.cpp b/src/gb/gbPrinter.cpp index 82843f29..13ac34cf 100644 --- a/src/gb/gbPrinter.cpp +++ b/src/gb/gbPrinter.cpp @@ -1,10 +1,10 @@ -#include -#include #include "../System.h" +#include +#include u8 gbPrinterStatus = 0; int gbPrinterState = 0; -u8 gbPrinterData[0x280*9]; +u8 gbPrinterData[0x280 * 9]; u8 gbPrinterPacket[0x400]; int gbPrinterCount = 0; int gbPrinterDataCount = 0; @@ -13,37 +13,36 @@ int gbPrinterResult = 0; bool gbPrinterCheckCRC() { - u16 crc = 0; + u16 crc = 0; - for(int i = 2; i < (6+gbPrinterDataSize); i++) { - crc += gbPrinterPacket[i]; - } + for (int i = 2; i < (6 + gbPrinterDataSize); i++) { + crc += gbPrinterPacket[i]; + } - int msgCrc = gbPrinterPacket[6+gbPrinterDataSize] + - (gbPrinterPacket[7+gbPrinterDataSize]<<8); + int msgCrc = gbPrinterPacket[6 + gbPrinterDataSize] + (gbPrinterPacket[7 + gbPrinterDataSize] << 8); - return msgCrc == crc; + return msgCrc == crc; } void gbPrinterReset() { - gbPrinterState = 0; - gbPrinterDataSize = 0; - gbPrinterDataCount = 0; - gbPrinterCount = 0; - gbPrinterStatus = 0; - gbPrinterResult = 0; + gbPrinterState = 0; + gbPrinterDataSize = 0; + gbPrinterDataCount = 0; + gbPrinterCount = 0; + gbPrinterStatus = 0; + gbPrinterResult = 0; } void gbPrinterShowData() { - systemGbPrint(gbPrinterData, - gbPrinterDataCount, - gbPrinterPacket[6], - gbPrinterPacket[7], - gbPrinterPacket[8], - gbPrinterPacket[9]); - /* + systemGbPrint(gbPrinterData, + gbPrinterDataCount, + gbPrinterPacket[6], + gbPrinterPacket[7], + gbPrinterPacket[8], + gbPrinterPacket[9]); + /* allegro_init(); install_keyboard(); set_gfx_mode(GFX_AUTODETECT, 160, 144, 0, 0); @@ -89,126 +88,126 @@ void gbPrinterShowData() void gbPrinterReceiveData() { int i = gbPrinterDataCount; - 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 += 2; - dest += control; - } else { // raw data - control++; - memcpy(dest, data, control); - dest += control; - data += control; - len += control + 1; - } + 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 += 2; + dest += control; + } else { // raw data + control++; + memcpy(dest, data, control); + dest += control; + data += control; + len += control + 1; + } + } + gbPrinterDataCount = (int)(dest - gbPrinterData); + } else { + memcpy(&gbPrinterData[gbPrinterDataCount], + &gbPrinterPacket[6], + gbPrinterDataSize); + gbPrinterDataCount += gbPrinterDataSize; } - gbPrinterDataCount = (int)(dest - gbPrinterData); - } 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; - } + 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 b) { - switch(gbPrinterState) { - case 0: - gbPrinterCount = 0; - // receiving preamble - if(b == 0x88) { - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterState++; - } else { - // todo: handle failure - gbPrinterReset(); - } - break; - case 1: - // receiving preamble - if(b == 0x33) { - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterState++; - } else { - // todo: handle failure - gbPrinterReset(); - } - break; - case 2: - // receiving header - gbPrinterPacket[gbPrinterCount++] = b; - if(gbPrinterCount == 6) { - gbPrinterState++; - gbPrinterDataSize = gbPrinterPacket[4] + (gbPrinterPacket[5]<<8); - } - break; - case 3: - // receiving data - if(gbPrinterDataSize) { - gbPrinterPacket[gbPrinterCount++] = b; - if(gbPrinterCount == (6+gbPrinterDataSize)) { + switch (gbPrinterState) { + case 0: + gbPrinterCount = 0; + // receiving preamble + if (b == 0x88) { + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterState++; + } else { + // todo: handle failure + gbPrinterReset(); + } + break; + case 1: + // receiving preamble + if (b == 0x33) { + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterState++; + } else { + // todo: handle failure + gbPrinterReset(); + } + break; + case 2: + // receiving header + gbPrinterPacket[gbPrinterCount++] = b; + if (gbPrinterCount == 6) { + gbPrinterState++; + gbPrinterDataSize = gbPrinterPacket[4] + (gbPrinterPacket[5] << 8); + } + break; + case 3: + // receiving data + if (gbPrinterDataSize) { + gbPrinterPacket[gbPrinterCount++] = b; + if (gbPrinterCount == (6 + gbPrinterDataSize)) { + gbPrinterState++; + } + break; + } gbPrinterState++; - } - break; - } - gbPrinterState++; // intentionally move to next if no data to receive - case 4: - // receiving CRC - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterState++; - break; - case 5: - // receiving CRC-2 - gbPrinterPacket[gbPrinterCount++] = b; - if(gbPrinterCheckCRC()) { - gbPrinterCommand(); + case 4: + // receiving CRC + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterState++; + break; + case 5: + // receiving CRC-2 + gbPrinterPacket[gbPrinterCount++] = b; + if (gbPrinterCheckCRC()) { + gbPrinterCommand(); + } + gbPrinterState++; + break; + case 6: + // receiving dummy 1 + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterResult = 0x81; + gbPrinterState++; + break; + case 7: + // receiving dummy 2 + gbPrinterPacket[gbPrinterCount++] = b; + gbPrinterResult = gbPrinterStatus; + gbPrinterState = 0; + gbPrinterCount = 0; + break; } - gbPrinterState++; - break; - case 6: - // receiving dummy 1 - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterResult = 0x81; - gbPrinterState++; - break; - case 7: - // receiving dummy 2 - gbPrinterPacket[gbPrinterCount++] = b; - gbPrinterResult = gbPrinterStatus; - gbPrinterState = 0; - gbPrinterCount = 0; - break; - } - return gbPrinterResult; + return gbPrinterResult; } diff --git a/src/gb/gbSGB.cpp b/src/gb/gbSGB.cpp index 2a72bc58..018d84d7 100644 --- a/src/gb/gbSGB.cpp +++ b/src/gb/gbSGB.cpp @@ -1,907 +1,896 @@ -#include #include +#include #include "../System.h" -#include "../common/Port.h" #include "../Util.h" +#include "../common/Port.h" #include "gb.h" #include "gbGlobals.h" -extern u8 *pix; +extern u8* pix; extern bool speedup; extern bool gbSgbResetFlag; -#define GBSGB_NONE 0 -#define GBSGB_RESET 1 +#define GBSGB_NONE 0 +#define GBSGB_RESET 1 #define GBSGB_PACKET_TRANSMIT 2 -u8 *gbSgbBorderChar = NULL; -u8 *gbSgbBorder = NULL; +u8* gbSgbBorderChar = NULL; +u8* gbSgbBorder = NULL; -int gbSgbCGBSupport = 0; -int gbSgbMask = 0; -int gbSgbMode = 0; -int gbSgbPacketState = GBSGB_NONE; -int gbSgbBit = 0; -int gbSgbPacketTimeout = 0; -int GBSGB_PACKET_TIMEOUT = 66666; -u8 gbSgbPacket[16*7]; -int gbSgbPacketNBits = 0; -int gbSgbPacketByte = 0; -int gbSgbPacketNumber = 0; -int gbSgbMultiplayer = 0; -int gbSgbFourPlayers = 0; -u8 gbSgbNextController = 0x0f; -u8 gbSgbReadingController = 0; -u16 gbSgbSCPPalette[4*512]; -u8 gbSgbATF[20 * 18]; -u8 gbSgbATFList[45 * 20 * 18]; -u8 gbSgbScreenBuffer[4160]; +int gbSgbCGBSupport = 0; +int gbSgbMask = 0; +int gbSgbMode = 0; +int gbSgbPacketState = GBSGB_NONE; +int gbSgbBit = 0; +int gbSgbPacketTimeout = 0; +int GBSGB_PACKET_TIMEOUT = 66666; +u8 gbSgbPacket[16 * 7]; +int gbSgbPacketNBits = 0; +int gbSgbPacketByte = 0; +int gbSgbPacketNumber = 0; +int gbSgbMultiplayer = 0; +int 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) +inline void gbSgbDraw24Bit(u8* p, u16 v) { - memcpy(p, &systemColorMap32[v], 3); + memcpy(p, &systemColorMap32[v], 3); } -inline void gbSgbDraw32Bit(u32 *p, u16 v) +inline void gbSgbDraw32Bit(u32* p, u16 v) { - *p = systemColorMap32[v]; + *p = systemColorMap32[v]; } -inline void gbSgbDraw16Bit(u16 *p, u16 v) +inline void gbSgbDraw16Bit(u16* p, u16 v) { - *p = systemColorMap16[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; + 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); + 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; - } + int i; + for (i = 1; i < 2048; i += 2) { + gbSgbBorder[i] = 1 << 2; + } - for(i = 0; i < 32; 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; - } + for (i = 0; i < 32; 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() { - gbSgbBorderChar = (u8 *)malloc(32 * 256); - gbSgbBorder = (u8 *)malloc(2048); + gbSgbBorderChar = (u8*)malloc(32 * 256); + gbSgbBorder = (u8*)malloc(2048); - gbSgbReset(); + gbSgbReset(); } void gbSgbShutdown() { - if(gbSgbBorderChar != NULL) { - free(gbSgbBorderChar); - gbSgbBorderChar = NULL; - } + if (gbSgbBorderChar != NULL) { + free(gbSgbBorderChar); + gbSgbBorderChar = NULL; + } - if(gbSgbBorder != NULL) { - free(gbSgbBorder); - gbSgbBorder = NULL; - } + if (gbSgbBorder != NULL) { + free(gbSgbBorder); + gbSgbBorder = NULL; + } } 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; + 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 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; + 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; } - break; - } } -#define getmem(x) gbMemoryMap[(x) >> 12][(x) & 0xfff] +#define getmem(x) gbMemoryMap[(x) >> 12][(x)&0xfff] void gbSgbRenderScreenToBuffer() { - u16 mapAddress = 0x9800; + u16 mapAddress = 0x9800; - if(register_LCDC & 0x08) - mapAddress = 0x9c00; + if (register_LCDC & 0x08) + mapAddress = 0x9c00; - u16 patternAddress = 0x8800; + u16 patternAddress = 0x8800; - int flag = 1; + 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 = getmem(mapAddress); - mapAddress++; - - if(flag) { - if(tile > 127) - tile -= 128; - else - tile += 128; - } - for(int k = 0; k < 16; k++) - *toAddress++ = getmem(patternAddress + tile*16 + k); + 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 = getmem(mapAddress); + mapAddress++; + + if (flag) { + if (tile > 127) + tile -= 128; + else + tile += 128; + } + for (int k = 0; k < 16; k++) + *toAddress++ = getmem(patternAddress + tile * 16 + k); + } + mapAddress += 12; } - 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; + 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* tileAddress = &gbSgbBorderChar[tile * 32]; + u8* tileAddress2 = &gbSgbBorderChar[tile * 32 + 16]; - u8 l = 8; + u8 l = 8; - u8 palette = ((attr >> 2 ) & 7); + u8 palette = ((attr >> 2) & 7); - if(palette < 4) - palette += 4; + if (palette < 4) + palette += 4; - palette *= 16; + palette *= 16; - u8 xx = 0; - u8 yy = 0; + u8 xx = 0; + u8 yy = 0; - int flipX = attr & 0x40; - int flipY = attr & 0x80; + 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 (l > 0) { + u8 mask = 0x80; + u8 a = *tileAddress++; + u8 b = *tileAddress++; + u8 c = *tileAddress2++; + u8 d = *tileAddress2++; - - - u8 yyy; - if(!flipY) - yyy = yy; - else - yyy = 7 - yy; - - 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; - - if (color || (y + yy < 40 || y + yy >= 184) || (x + xx < 48 || x + xx >= 208)) { - u8 xxx; - - if(!flipX) - xxx = xx; + u8 yyy; + if (!flipY) + yyy = yy; else - xxx = 7 - xx; + yyy = 7 - yy; - u16 cc; - if (color) { - cc = gbPalette[palette + color]; - } else { - cc = gbPalette[0]; + 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; + + if (color || (y + yy < 40 || y + yy >= 184) || (x + xx < 48 || x + xx >= 208)) { + u8 xxx; + + if (!flipX) + xxx = xx; + else + xxx = 7 - xx; + + u16 cc; + if (color) { + cc = gbPalette[palette + color]; + } else { + cc = gbPalette[0]; + } + + switch (systemColorDepth) { + case 16: + gbSgbDraw16Bit(dest + yyy * (256 + 2) + xxx, cc); + break; + case 24: + gbSgbDraw24Bit(dest8 + (yyy * 256 + xxx) * 3, cc); + break; + case 32: + gbSgbDraw32Bit(dest32 + yyy * (256 + 1) + xxx, cc); + break; + } + } + + mask >>= 1; + + xx++; } - - switch(systemColorDepth) { - case 16: - gbSgbDraw16Bit(dest + yyy*(256+2) + xxx, cc); - break; - case 24: - gbSgbDraw24Bit(dest8 + (yyy*256+xxx)*3, cc); - break; - case 32: - gbSgbDraw32Bit(dest32 + yyy*(256+1)+xxx, cc); - break; - } - } - - mask >>= 1; - - xx++; + yy++; + xx = 0; + l--; + mask = 0x80; } - yy++; - xx = 0; - l--; - mask = 0x80; - } } void gbSgbRenderBorder() { - if(gbBorderOn) { - u8 *fromAddress = gbSgbBorder; + 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++; + 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); - } + gbSgbDrawBorderTile(x * 8, y * 8, tile, attr); + } + } } - } } void gbSgbPicture() { - gbSgbRenderScreenToBuffer(); + gbSgbRenderScreenToBuffer(); - memcpy(gbSgbBorder, gbSgbScreenBuffer, 2048); + memcpy(gbSgbBorder, gbSgbScreenBuffer, 2048); - u16 *paletteAddr = (u16 *)&gbSgbScreenBuffer[2048]; + u16* paletteAddr = (u16*)&gbSgbScreenBuffer[2048]; - for(int i = 64; i < 128; i++) { - gbPalette[i] = READ16LE(paletteAddr++); - } + for (int i = 64; i < 128; i++) { + gbPalette[i] = READ16LE(paletteAddr++); + } - gbSgbCGBSupport |= 4; + gbSgbCGBSupport |= 4; - if(gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) { - gbBorderOn = 1; - systemGbBorderOn(); - } + if (gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) { + gbBorderOn = 1; + systemGbBorderOn(); + } - if(gbBorderOn && !gbSgbMask) - gbSgbRenderBorder(); + if (gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); - if(gbSgbMode && gbCgbMode && gbSgbCGBSupport > 4) { - gbSgbCGBSupport = 0; - gbSgbMode = 0; - gbSgbMask = 0; - gbSgbRenderBorder(); - gbReset(); - } + if (gbSgbMode && gbCgbMode && gbSgbCGBSupport > 4) { + gbSgbCGBSupport = 0; + gbSgbMode = 0; + gbSgbMask = 0; + gbSgbRenderBorder(); + gbReset(); + } - if(gbSgbCGBSupport > 4) - gbSgbCGBSupport = 0; + if (gbSgbCGBSupport > 4) + gbSgbCGBSupport = 0; } -void gbSgbSetPalette(int a,int b,u16 *p) +void gbSgbSetPalette(int a, int b, u16* p) { - u16 bit00 = READ16LE(p++); - int i; + 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[a * 4 + i] = READ16LE(p++); + } - for(i = 1; i < 4; i++) { - gbPalette[b*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(); + gbPalette[0] = gbPalette[4] = gbPalette[8] = gbPalette[12] = bit00; + if (gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); } void gbSgbScpPalette() { - gbSgbRenderScreenToBuffer(); + gbSgbRenderScreenToBuffer(); - u16 *fromAddress = (u16 *)gbSgbScreenBuffer; + u16* fromAddress = (u16*)gbSgbScreenBuffer; - for(int i = 0; i < 512*4; i++) { - gbSgbSCPPalette[i] = READ16LE(fromAddress++); - } + 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 (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(); - } + 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)); + 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[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[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)); + pal = READ16LE((((u16*)&gbSgbPacket[7]))) & 511; + memcpy(&gbPalette[12], &gbSgbSCPPalette[pal * 4], 4 * sizeof(u16)); - u8 atf = gbSgbPacket[9]; + u8 atf = gbSgbPacket[9]; - if(atf & 0x80) { - gbSgbSetATF(atf & 0x3f); - } + if (atf & 0x80) { + gbSgbSetATF(atf & 0x3f); + } - if(atf & 0x40) { - gbSgbMask = 0; - if(gbBorderOn) - gbSgbRenderBorder(); - } + if (atf & 0x40) { + gbSgbMask = 0; + if (gbBorderOn) + gbSgbRenderBorder(); + } } void gbSgbAttributeBlock() { - u8 *fromAddress = &gbSgbPacket[1]; + u8* fromAddress = &gbSgbPacket[1]; - u8 nDataSet = *fromAddress++; - if(nDataSet > 12) - nDataSet = 12; - if(nDataSet == 0) - nDataSet = 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; + 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; + 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; + 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++; + } } - toAddress++; - } + nDataSet--; } - nDataSet--; - } } void gbSgbSetColumnPalette(u8 col, u8 p) { - // if(col < 0) - // col = 0; - if(col > 19) - col = 19; + // if(col < 0) + // col = 0; + if (col > 19) + col = 19; - p &= 3; + p &= 3; - u8 *toAddress = &gbSgbATF[col]; + u8* toAddress = &gbSgbATF[col]; - for(u8 y = 0; y < 18; y++) { - *toAddress = p; - toAddress += 20; - } + 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; + // if(row < 0) + // row = 0; + if (row > 17) + row = 17; - p &= 3; + p &= 3; - u8 *toAddress = &gbSgbATF[row*20]; + u8* toAddress = &gbSgbATF[row * 20]; - for(u8 x = 0; x < 20; x++) { - *toAddress++ = p; - } + 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; + 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; + 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); + 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); + } } - } 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* fromAddress = &gbSgbPacket[1]; - u8 nDataSet = *fromAddress++; + u8 nDataSet = *fromAddress++; - if(nDataSet > 0x6e) - nDataSet = 0x6e; + 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); + 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--; } - 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 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++; + 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 (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--; - } + 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--; + } + } } - } 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(); + gbSgbRenderScreenToBuffer(); - u8 *fromAddress = gbSgbScreenBuffer; - u8 *toAddress = gbSgbATFList; + 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; - } + 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; + int gbSgbMaskFlag = gbSgbPacket[1] & 3; - gbSgbMask = gbSgbMaskFlag; + 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(); - } + 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(); + gbSgbRenderScreenToBuffer(); - int address = (gbSgbPacket[1] & 1) * (128*32); + int address = (gbSgbPacket[1] & 1) * (128 * 32); - if(gbSgbPacket[1] & 1) - gbSgbCGBSupport |= 2; - else - gbSgbCGBSupport |= 1; + if (gbSgbPacket[1] & 1) + gbSgbCGBSupport |= 2; + else + gbSgbCGBSupport |= 1; - memcpy(&gbSgbBorderChar[address], gbSgbScreenBuffer, 128 * 32); + memcpy(&gbSgbBorderChar[address], gbSgbScreenBuffer, 128 * 32); - if(gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) { - gbBorderOn = 1; - systemGbBorderOn(); - } + if (gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) { + gbBorderOn = 1; + systemGbBorderOn(); + } - if(gbBorderOn && !gbSgbMask) - gbSgbRenderBorder(); + if (gbBorderOn && !gbSgbMask) + gbSgbRenderBorder(); - if(gbSgbMode && gbCgbMode && gbSgbCGBSupport == 7) { - gbSgbCGBSupport = 0; - gbSgbMode = 0; - gbSgbMask = 0; - gbSgbRenderBorder(); - gbReset(); - } + if (gbSgbMode && gbCgbMode && gbSgbCGBSupport == 7) { + gbSgbCGBSupport = 0; + gbSgbMode = 0; + gbSgbMask = 0; + gbSgbRenderBorder(); + gbReset(); + } - if(gbSgbCGBSupport > 4) - gbSgbCGBSupport = 0; + 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; - } + 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; + 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; - } + 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; + 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; + 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 { - gbSgbReadingController &= 3; + if (value == 0x10) + gbSgbReadingController |= 0x2; + else if (value == 0x20) + gbSgbReadingController |= 0x01; + gbSgbPacketTimeout = 0; } - } - 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; + 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; } - } else { - if(gbSgbPacketNBits < 128) { - gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] >>= 1; - gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] |= gbSgbBit; - gbSgbPacketNBits++; - if(!(gbSgbPacketNBits & 7)) { - gbSgbPacketByte++; - } - gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + 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; } - } - } else { - if(value == 0x20) - gbSgbBit = 0x00; - else - gbSgbBit = 0x80; - gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT; + gbSgbReadingController = 0; + break; + default: + gbSgbPacketState = GBSGB_NONE; + gbSgbPacketTimeout = 0; + break; } - gbSgbReadingController = 0; - break; - default: - gbSgbPacketState = GBSGB_NONE; - gbSgbPacketTimeout = 0; - break; - } } variable_desc gbSgbSaveStruct[] = { - { &gbSgbMask, sizeof(int) }, - { &gbSgbPacketState, sizeof(int) }, - { &gbSgbBit, sizeof(int) }, - { &gbSgbPacketNBits, sizeof(int) }, - { &gbSgbPacketByte, sizeof(int) }, - { &gbSgbPacketNumber, sizeof(int) }, - { &gbSgbMultiplayer, sizeof(int) }, - { &gbSgbNextController, sizeof(u8) }, - { &gbSgbReadingController, sizeof(u8) }, - { NULL, 0 } + { &gbSgbMask, sizeof(int) }, + { &gbSgbPacketState, sizeof(int) }, + { &gbSgbBit, sizeof(int) }, + { &gbSgbPacketNBits, sizeof(int) }, + { &gbSgbPacketByte, sizeof(int) }, + { &gbSgbPacketNumber, sizeof(int) }, + { &gbSgbMultiplayer, sizeof(int) }, + { &gbSgbNextController, sizeof(u8) }, + { &gbSgbReadingController, sizeof(u8) }, + { NULL, 0 } }; variable_desc gbSgbSaveStructV3[] = { - { &gbSgbMask, sizeof(int) }, - { &gbSgbPacketState, sizeof(int) }, - { &gbSgbBit, sizeof(int) }, - { &gbSgbPacketNBits, sizeof(int) }, - { &gbSgbPacketByte, sizeof(int) }, - { &gbSgbPacketNumber, sizeof(int) }, - { &gbSgbMultiplayer, sizeof(int) }, - { &gbSgbNextController, sizeof(u8) }, - { &gbSgbReadingController, sizeof(u8) }, - { &gbSgbFourPlayers, sizeof(int) }, - { NULL, 0 } + { &gbSgbMask, sizeof(int) }, + { &gbSgbPacketState, sizeof(int) }, + { &gbSgbBit, sizeof(int) }, + { &gbSgbPacketNBits, sizeof(int) }, + { &gbSgbPacketByte, sizeof(int) }, + { &gbSgbPacketNumber, sizeof(int) }, + { &gbSgbMultiplayer, sizeof(int) }, + { &gbSgbNextController, sizeof(u8) }, + { &gbSgbReadingController, sizeof(u8) }, + { &gbSgbFourPlayers, sizeof(int) }, + { NULL, 0 } }; void gbSgbSaveGame(gzFile gzFile) { - utilWriteData(gzFile, gbSgbSaveStructV3); + utilWriteData(gzFile, gbSgbSaveStructV3); - utilGzWrite(gzFile, gbSgbBorder, 2048); - utilGzWrite(gzFile, gbSgbBorderChar, 32*256); + utilGzWrite(gzFile, gbSgbBorder, 2048); + utilGzWrite(gzFile, gbSgbBorderChar, 32 * 256); - utilGzWrite(gzFile, gbSgbPacket, 16*7); + 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, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); + utilGzWrite(gzFile, gbSgbATF, 20 * 18); + utilGzWrite(gzFile, gbSgbATFList, 45 * 20 * 18); } void gbSgbReadGame(gzFile gzFile, int version) { - if(version >= 3) - utilReadData(gzFile, gbSgbSaveStructV3); - else { - utilReadData(gzFile, gbSgbSaveStruct); - gbSgbFourPlayers = 0; - } + if (version >= 3) + utilReadData(gzFile, gbSgbSaveStructV3); + else { + utilReadData(gzFile, gbSgbSaveStruct); + gbSgbFourPlayers = 0; + } - if(version >= 8) { - utilGzRead(gzFile, gbSgbBorder, 2048); - utilGzRead(gzFile, gbSgbBorderChar, 32*256); - } + if (version >= 8) { + utilGzRead(gzFile, gbSgbBorder, 2048); + utilGzRead(gzFile, gbSgbBorderChar, 32 * 256); + } - utilGzRead(gzFile, gbSgbPacket, 16*7); + utilGzRead(gzFile, gbSgbPacket, 16 * 7); - utilGzRead(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); - utilGzRead(gzFile, gbSgbATF, 20 * 18); - utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18); + utilGzRead(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16)); + utilGzRead(gzFile, gbSgbATF, 20 * 18); + utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18); } diff --git a/src/gb/gbSound.cpp b/src/gb/gbSound.cpp index a1209c6c..3e267b35 100644 --- a/src/gb/gbSound.cpp +++ b/src/gb/gbSound.cpp @@ -1,443 +1,456 @@ #include -#include "../gba/Sound.h" #include "../Util.h" +#include "../gba/Sound.h" +#include "gb.h" #include "gbGlobals.h" #include "gbSound.h" -#include "gb.h" -#include "../apu/Gb_Apu.h" #include "../apu/Effects_Buffer.h" +#include "../apu/Gb_Apu.h" extern long soundSampleRate; // current sound quality gb_effects_config_t gb_effects_config = { false, 0.20f, 0.15f, false }; -static gb_effects_config_t gb_effects_config_current; +static gb_effects_config_t gb_effects_config_current; static Simple_Effects_Buffer* stereo_buffer; -static Gb_Apu* gb_apu; +static Gb_Apu* gb_apu; -static float soundVolume_ = -1; +static float soundVolume_ = -1; static int prevSoundEnable = -1; -static bool declicking = false; +static bool declicking = false; int const chan_count = 4; int const ticks_to_time = 2 * GB_APU_OVERCLOCK; static inline blip_time_t blip_time() { - return (SOUND_CLOCK_TICKS - soundTicks) * ticks_to_time; + return (SOUND_CLOCK_TICKS - soundTicks) * ticks_to_time; } -u8 gbSoundRead( u16 address ) +u8 gbSoundRead(u16 address) { - if ( gb_apu && address >= NR10 && address <= 0xFF3F ) - return gb_apu->read_register( blip_time(), address ); + if (gb_apu && address >= NR10 && address <= 0xFF3F) + return gb_apu->read_register(blip_time(), address); - return gbMemory[address]; + return gbMemory[address]; } void gbSoundEvent(register u16 address, register int data) { - gbMemory[address] = data; + gbMemory[address] = data; - if ( gb_apu && address >= NR10 && address <= 0xFF3F ) - gb_apu->write_register( blip_time(), address, data ); + if (gb_apu && address >= NR10 && address <= 0xFF3F) + gb_apu->write_register(blip_time(), address, data); } -static void end_frame( blip_time_t time ) +static void end_frame(blip_time_t time) { - gb_apu ->end_frame( time ); - stereo_buffer->end_frame( time ); + gb_apu->end_frame(time); + stereo_buffer->end_frame(time); } static void apply_effects() { - prevSoundEnable = soundGetEnable(); - gb_effects_config_current = gb_effects_config; + prevSoundEnable = soundGetEnable(); + gb_effects_config_current = gb_effects_config; - stereo_buffer->config().enabled = gb_effects_config_current.enabled; - stereo_buffer->config().echo = gb_effects_config_current.echo; - stereo_buffer->config().stereo = gb_effects_config_current.stereo; - stereo_buffer->config().surround = gb_effects_config_current.surround; - stereo_buffer->apply_config(); + stereo_buffer->config().enabled = gb_effects_config_current.enabled; + stereo_buffer->config().echo = gb_effects_config_current.echo; + stereo_buffer->config().stereo = gb_effects_config_current.stereo; + stereo_buffer->config().surround = gb_effects_config_current.surround; + stereo_buffer->apply_config(); - for ( int i = 0; i < chan_count; i++ ) - { - Multi_Buffer::channel_t ch = { 0, 0, 0 }; - if ( prevSoundEnable >> i & 1 ) - ch = stereo_buffer->channel( i ); - gb_apu->set_output( ch.center, ch.left, ch.right, i ); - } + for (int i = 0; i < chan_count; i++) { + Multi_Buffer::channel_t ch = { 0, 0, 0 }; + if (prevSoundEnable >> i & 1) + ch = stereo_buffer->channel(i); + gb_apu->set_output(ch.center, ch.left, ch.right, i); + } } -void gbSoundConfigEffects( gb_effects_config_t const& c ) +void gbSoundConfigEffects(gb_effects_config_t const& c) { - gb_effects_config = c; + gb_effects_config = c; } static void apply_volume() { - soundVolume_ = soundGetVolume(); + soundVolume_ = soundGetVolume(); - if ( gb_apu ) - gb_apu->volume( soundVolume_ ); + if (gb_apu) + gb_apu->volume(soundVolume_); } void gbSoundTick() { - if ( gb_apu && stereo_buffer ) - { - // Run sound hardware to present - end_frame( SOUND_CLOCK_TICKS * ticks_to_time ); + if (gb_apu && stereo_buffer) { + // Run sound hardware to present + end_frame(SOUND_CLOCK_TICKS * ticks_to_time); - flush_samples(stereo_buffer); + flush_samples(stereo_buffer); - // Update effects config if it was changed - if ( memcmp( &gb_effects_config_current, &gb_effects_config, - sizeof gb_effects_config ) || soundGetEnable() != prevSoundEnable ) - apply_effects(); + // Update effects config if it was changed + if (memcmp(&gb_effects_config_current, &gb_effects_config, + sizeof gb_effects_config) + || soundGetEnable() != prevSoundEnable) + apply_effects(); - if ( soundVolume_ != soundGetVolume() ) - apply_volume(); - } + if (soundVolume_ != soundGetVolume()) + apply_volume(); + } } static void reset_apu() { - Gb_Apu::mode_t mode = Gb_Apu::mode_dmg; - if ( gbHardware & 2 ) - mode = Gb_Apu::mode_cgb; - if ( gbHardware & 8 || declicking ) - mode = Gb_Apu::mode_agb; - gb_apu->reset( mode ); - gb_apu->reduce_clicks( declicking ); + Gb_Apu::mode_t mode = Gb_Apu::mode_dmg; + if (gbHardware & 2) + mode = Gb_Apu::mode_cgb; + if (gbHardware & 8 || declicking) + mode = Gb_Apu::mode_agb; + gb_apu->reset(mode); + gb_apu->reduce_clicks(declicking); - if ( stereo_buffer ) - stereo_buffer->clear(); + if (stereo_buffer) + stereo_buffer->clear(); - soundTicks = SOUND_CLOCK_TICKS; + soundTicks = SOUND_CLOCK_TICKS; } static void remake_stereo_buffer() { - // APU - if ( !gb_apu ) - { - gb_apu = new Gb_Apu; // TODO: handle errors - reset_apu(); - } + // APU + if (!gb_apu) { + gb_apu = new Gb_Apu; // TODO: handle errors + reset_apu(); + } - // Stereo_Buffer - delete stereo_buffer; - stereo_buffer = 0; + // Stereo_Buffer + delete stereo_buffer; + stereo_buffer = 0; - stereo_buffer = new Simple_Effects_Buffer; // TODO: handle out of memory - if ( stereo_buffer->set_sample_rate( soundSampleRate ) ) { } // TODO: handle out of memory - stereo_buffer->clock_rate( gb_apu->clock_rate ); - - // Multi_Buffer - static int const chan_types [chan_count] = { - Multi_Buffer::wave_type+1, Multi_Buffer::wave_type+2, - Multi_Buffer::wave_type+3, Multi_Buffer::mixed_type+1 - }; - if ( stereo_buffer->set_channel_count( chan_count, chan_types ) ) { } // TODO: handle errors + stereo_buffer = new Simple_Effects_Buffer; // TODO: handle out of memory + if (stereo_buffer->set_sample_rate(soundSampleRate)) { + } // TODO: handle out of memory + stereo_buffer->clock_rate(gb_apu->clock_rate); - // Volume Level - apply_effects(); - apply_volume(); + // Multi_Buffer + static int const chan_types[chan_count] = { + Multi_Buffer::wave_type + 1, Multi_Buffer::wave_type + 2, + Multi_Buffer::wave_type + 3, Multi_Buffer::mixed_type + 1 + }; + if (stereo_buffer->set_channel_count(chan_count, chan_types)) { + } // TODO: handle errors + + // Volume Level + apply_effects(); + apply_volume(); } -void gbSoundSetDeclicking( bool enable ) +void gbSoundSetDeclicking(bool enable) { - if ( declicking != enable ) - { - declicking = enable; - if ( gb_apu ) - { - // Can't change sound hardware mode without resetting APU, so save/load - // state around mode change - gb_apu_state_t state; - gb_apu->save_state( &state ); - reset_apu(); - if ( gb_apu->load_state( state ) ) { } // ignore error - } - } + if (declicking != enable) { + declicking = enable; + if (gb_apu) { + // Can't change sound hardware mode without resetting APU, so save/load + // state around mode change + gb_apu_state_t state; + gb_apu->save_state(&state); + reset_apu(); + if (gb_apu->load_state(state)) { + } // ignore error + } + } } bool gbSoundGetDeclicking() { - return declicking; + return declicking; } void gbSoundReset() { - SOUND_CLOCK_TICKS = 20000; // 1/100 second + SOUND_CLOCK_TICKS = 20000; // 1/100 second - remake_stereo_buffer(); - reset_apu(); + remake_stereo_buffer(); + reset_apu(); - soundPaused = 1; + soundPaused = 1; - gbSoundEvent(0xff10, 0x80); - gbSoundEvent(0xff11, 0xbf); - gbSoundEvent(0xff12, 0xf3); - gbSoundEvent(0xff14, 0xbf); - gbSoundEvent(0xff16, 0x3f); - gbSoundEvent(0xff17, 0x00); - gbSoundEvent(0xff19, 0xbf); + 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(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(0xff20, 0xff); + gbSoundEvent(0xff21, 0x00); + gbSoundEvent(0xff22, 0x00); + gbSoundEvent(0xff23, 0xbf); + gbSoundEvent(0xff24, 0x77); + gbSoundEvent(0xff25, 0xf3); - if (gbHardware & 0x4) - gbSoundEvent(0xff26, 0xf0); - else - gbSoundEvent(0xff26, 0xf1); + if (gbHardware & 0x4) + gbSoundEvent(0xff26, 0xf0); + else + gbSoundEvent(0xff26, 0xf1); - /* workaround for game Beetlejuice */ - if (gbHardware & 0x1) { - gbSoundEvent(0xff24, 0x77); - gbSoundEvent(0xff25, 0xf3); - } + /* workaround for game Beetlejuice */ + if (gbHardware & 0x1) { + gbSoundEvent(0xff24, 0x77); + gbSoundEvent(0xff25, 0xf3); + } - int addr = 0xff30; + int addr = 0xff30; - while(addr < 0xff40) { - gbMemory[addr++] = 0x00; - gbMemory[addr++] = 0xff; - } + while (addr < 0xff40) { + gbMemory[addr++] = 0x00; + gbMemory[addr++] = 0xff; + } } -void gbSoundSetSampleRate( long sampleRate ) +void gbSoundSetSampleRate(long sampleRate) { - if ( soundSampleRate != sampleRate ) - { - if ( systemCanChangeSoundQuality() ) - { - soundShutdown(); - soundSampleRate = sampleRate; - soundInit(); - } - else - { - soundSampleRate = sampleRate; - } + if (soundSampleRate != sampleRate) { + if (systemCanChangeSoundQuality()) { + soundShutdown(); + soundSampleRate = sampleRate; + soundInit(); + } else { + soundSampleRate = sampleRate; + } - remake_stereo_buffer(); - } + remake_stereo_buffer(); + } } static struct { - int version; - gb_apu_state_t apu; + int version; + gb_apu_state_t apu; } state; -static char dummy_state [735 * 2]; +static char dummy_state[735 * 2]; -#define SKIP( type, name ) { dummy_state, sizeof (type) } +#define SKIP(type, name) \ + { \ + dummy_state, sizeof(type) \ + } -#define LOAD( type, name ) { &name, sizeof (type) } +#define LOAD(type, name) \ + { \ + &name, sizeof(type) \ + } // Old save state support -static variable_desc gbsound_format [] = -{ - SKIP( int, soundPaused ), - SKIP( int, soundPlay ), - SKIP( int, soundTicks ), - SKIP( int, SOUND_CLOCK_TICKS ), - SKIP( int, soundLevel1 ), - SKIP( int, soundLevel2 ), - SKIP( int, soundBalance ), - SKIP( int, soundMasterOn ), - SKIP( int, soundIndex ), - SKIP( int, soundVIN ), - SKIP( int, soundOn [0] ), - SKIP( int, soundATL [0] ), - SKIP( int, sound1Skip ), - SKIP( int, soundIndex [0] ), - SKIP( int, sound1Continue ), - SKIP( int, soundEnvelopeVolume [0] ), - SKIP( int, soundEnvelopeATL [0] ), - SKIP( int, sound1EnvelopeATLReload ), - SKIP( int, sound1EnvelopeUpDown ), - SKIP( int, sound1SweepATL ), - SKIP( int, sound1SweepATLReload ), - SKIP( int, sound1SweepSteps ), - SKIP( int, sound1SweepUpDown ), - SKIP( int, sound1SweepStep ), - SKIP( int, soundOn [1] ), - SKIP( int, soundATL [1] ), - SKIP( int, sound2Skip ), - SKIP( int, soundIndex [1] ), - SKIP( int, sound2Continue ), - SKIP( int, soundEnvelopeVolume [1] ), - SKIP( int, soundEnvelopeATL [1] ), - SKIP( int, sound2EnvelopeATLReload ), - SKIP( int, sound2EnvelopeUpDown ), - SKIP( int, soundOn [2] ), - SKIP( int, soundATL [2] ), - SKIP( int, sound3Skip ), - SKIP( int, soundIndex [2] ), - SKIP( int, sound3Continue ), - SKIP( int, sound3OutputLevel ), - SKIP( int, soundOn [3] ), - SKIP( int, soundATL [3] ), - SKIP( int, sound4Skip ), - SKIP( int, soundIndex [3] ), - SKIP( int, sound4Clock ), - SKIP( int, sound4ShiftRight ), - SKIP( int, sound4ShiftSkip ), - SKIP( int, sound4ShiftIndex ), - SKIP( int, sound4NSteps ), - SKIP( int, sound4CountDown ), - SKIP( int, sound4Continue ), - SKIP( int, soundEnvelopeVolume [2] ), - SKIP( int, soundEnvelopeATL [2] ), - SKIP( int, sound4EnvelopeATLReload ), - SKIP( int, sound4EnvelopeUpDown ), - SKIP( int, soundEnableFlag ), - { NULL, 0 } +static variable_desc gbsound_format[] = { + SKIP(int, soundPaused), + SKIP(int, soundPlay), + SKIP(int, soundTicks), + SKIP(int, SOUND_CLOCK_TICKS), + SKIP(int, soundLevel1), + SKIP(int, soundLevel2), + SKIP(int, soundBalance), + SKIP(int, soundMasterOn), + SKIP(int, soundIndex), + SKIP(int, soundVIN), + SKIP(int, soundOn[0]), + SKIP(int, soundATL[0]), + SKIP(int, sound1Skip), + SKIP(int, soundIndex[0]), + SKIP(int, sound1Continue), + SKIP(int, soundEnvelopeVolume[0]), + SKIP(int, soundEnvelopeATL[0]), + SKIP(int, sound1EnvelopeATLReload), + SKIP(int, sound1EnvelopeUpDown), + SKIP(int, sound1SweepATL), + SKIP(int, sound1SweepATLReload), + SKIP(int, sound1SweepSteps), + SKIP(int, sound1SweepUpDown), + SKIP(int, sound1SweepStep), + SKIP(int, soundOn[1]), + SKIP(int, soundATL[1]), + SKIP(int, sound2Skip), + SKIP(int, soundIndex[1]), + SKIP(int, sound2Continue), + SKIP(int, soundEnvelopeVolume[1]), + SKIP(int, soundEnvelopeATL[1]), + SKIP(int, sound2EnvelopeATLReload), + SKIP(int, sound2EnvelopeUpDown), + SKIP(int, soundOn[2]), + SKIP(int, soundATL[2]), + SKIP(int, sound3Skip), + SKIP(int, soundIndex[2]), + SKIP(int, sound3Continue), + SKIP(int, sound3OutputLevel), + SKIP(int, soundOn[3]), + SKIP(int, soundATL[3]), + SKIP(int, sound4Skip), + SKIP(int, soundIndex[3]), + SKIP(int, sound4Clock), + SKIP(int, sound4ShiftRight), + SKIP(int, sound4ShiftSkip), + SKIP(int, sound4ShiftIndex), + SKIP(int, sound4NSteps), + SKIP(int, sound4CountDown), + SKIP(int, sound4Continue), + SKIP(int, soundEnvelopeVolume[2]), + SKIP(int, soundEnvelopeATL[2]), + SKIP(int, sound4EnvelopeATLReload), + SKIP(int, sound4EnvelopeUpDown), + SKIP(int, soundEnableFlag), + { NULL, 0 } }; -static variable_desc gbsound_format2 [] = -{ - SKIP( int, sound1ATLreload ), - SKIP( int, freq1low ), - SKIP( int, freq1high ), - SKIP( int, sound2ATLreload ), - SKIP( int, freq2low ), - SKIP( int, freq2high ), - SKIP( int, sound3ATLreload ), - SKIP( int, freq3low ), - SKIP( int, freq3high ), - SKIP( int, sound4ATLreload ), - SKIP( int, freq4 ), - { NULL, 0 } +static variable_desc gbsound_format2[] = { + SKIP(int, sound1ATLreload), + SKIP(int, freq1low), + SKIP(int, freq1high), + SKIP(int, sound2ATLreload), + SKIP(int, freq2low), + SKIP(int, freq2high), + SKIP(int, sound3ATLreload), + SKIP(int, freq3low), + SKIP(int, freq3high), + SKIP(int, sound4ATLreload), + SKIP(int, freq4), + { NULL, 0 } }; -static variable_desc gbsound_format3 [] = -{ - SKIP( u8[2*735], soundBuffer ), - SKIP( u8[2*735], soundBuffer ), - SKIP( u16[735], soundFinalWave ), - { NULL, 0 } +static variable_desc gbsound_format3[] = { + SKIP(u8[2 * 735], soundBuffer), + SKIP(u8[2 * 735], soundBuffer), + SKIP(u16[735], soundFinalWave), + { NULL, 0 } }; enum { - nr10 = 0, - nr11, nr12, nr13, nr14, - nr20, nr21, nr22, nr23, nr24, - nr30, nr31, nr32, nr33, nr34, - nr40, nr41, nr42, nr43, nr44, - nr50, nr51, nr52 + nr10 = 0, + nr11, + nr12, + nr13, + nr14, + nr20, + nr21, + nr22, + nr23, + nr24, + nr30, + nr31, + nr32, + nr33, + nr34, + nr40, + nr41, + nr42, + nr43, + nr44, + nr50, + nr51, + nr52 }; -static void gbSoundReadGameOld(int version,gzFile gzFile) +static void gbSoundReadGameOld(int version, gzFile gzFile) { - if ( version == 11 ) - { - // Version 11 didn't save any state - // TODO: same for version 10? - state.apu.regs [nr50] = 0x77; // volume at max - state.apu.regs [nr51] = 0xFF; // channels enabled - state.apu.regs [nr52] = 0x80; // power on - return; - } + if (version == 11) { + // Version 11 didn't save any state + // TODO: same for version 10? + state.apu.regs[nr50] = 0x77; // volume at max + state.apu.regs[nr51] = 0xFF; // channels enabled + state.apu.regs[nr52] = 0x80; // power on + return; + } - // Load state - utilReadData( gzFile, gbsound_format ); + // Load state + utilReadData(gzFile, gbsound_format); - if ( version >= 11 ) // TODO: never executed; remove? - utilReadData( gzFile, gbsound_format2 ); + if (version >= 11) // TODO: never executed; remove? + utilReadData(gzFile, gbsound_format2); - utilReadData( gzFile, gbsound_format3 ); + utilReadData(gzFile, gbsound_format3); - int quality = 1; - if ( version >= 7 ) - quality = utilReadInt( gzFile ); + int quality = 1; + if (version >= 7) + quality = utilReadInt(gzFile); - gbSoundSetSampleRate( 44100 / quality ); + gbSoundSetSampleRate(44100 / quality); - // Convert to format Gb_Apu uses - gb_apu_state_t& s = state.apu; + // Convert to format Gb_Apu uses + gb_apu_state_t& s = state.apu; - // Only some registers are properly preserved - static int const regs_to_copy [] = { - nr10, nr11, nr12, nr21, nr22, nr30, nr32, nr42, nr43, nr50, nr51, nr52, -1 - }; - for ( int i = 0; regs_to_copy [i] >= 0; i++ ) - s.regs [regs_to_copy [i]] = gbMemory [0xFF10 + regs_to_copy [i]]; + // Only some registers are properly preserved + static int const regs_to_copy[] = { + nr10, nr11, nr12, nr21, nr22, nr30, nr32, nr42, nr43, nr50, nr51, nr52, -1 + }; + for (int i = 0; regs_to_copy[i] >= 0; i++) + s.regs[regs_to_copy[i]] = gbMemory[0xFF10 + regs_to_copy[i]]; - memcpy( &s.regs [0x20], &gbMemory [0xFF30], 0x10 ); // wave + memcpy(&s.regs[0x20], &gbMemory[0xFF30], 0x10); // wave } // New state format -static variable_desc gb_state [] = -{ - LOAD( int, state.version ), // room_for_expansion will be used by later versions +static variable_desc gb_state[] = { + LOAD(int, state.version), // room_for_expansion will be used by later versions - // APU - LOAD( u8 [0x40], state.apu.regs ), // last values written to registers and wave RAM (both banks) - LOAD( int, state.apu.frame_time ), // clocks until next frame sequencer action - LOAD( int, state.apu.frame_phase ), // next step frame sequencer will run + // APU + LOAD(u8[0x40], state.apu.regs), // last values written to registers and wave RAM (both banks) + LOAD(int, state.apu.frame_time), // clocks until next frame sequencer action + LOAD(int, state.apu.frame_phase), // next step frame sequencer will run - LOAD( int, state.apu.sweep_freq ), // sweep's internal frequency register - LOAD( int, state.apu.sweep_delay ), // clocks until next sweep action - LOAD( int, state.apu.sweep_enabled ), - LOAD( int, state.apu.sweep_neg ), // obscure internal flag - LOAD( int, state.apu.noise_divider ), - LOAD( int, state.apu.wave_buf ), // last read byte of wave RAM + LOAD(int, state.apu.sweep_freq), // sweep's internal frequency register + LOAD(int, state.apu.sweep_delay), // clocks until next sweep action + LOAD(int, state.apu.sweep_enabled), + LOAD(int, state.apu.sweep_neg), // obscure internal flag + LOAD(int, state.apu.noise_divider), + LOAD(int, state.apu.wave_buf), // last read byte of wave RAM - LOAD( int [4], state.apu.delay ), // clocks until next channel action - LOAD( int [4], state.apu.length_ctr ), - LOAD( int [4], state.apu.phase ), // square/wave phase, noise LFSR - LOAD( int [4], state.apu.enabled ), // internal enabled flag + LOAD(int[4], state.apu.delay), // clocks until next channel action + LOAD(int[4], state.apu.length_ctr), + LOAD(int[4], state.apu.phase), // square/wave phase, noise LFSR + LOAD(int[4], state.apu.enabled), // internal enabled flag - LOAD( int [3], state.apu.env_delay ), // clocks until next envelope action - LOAD( int [3], state.apu.env_volume ), - LOAD( int [3], state.apu.env_enabled ), + LOAD(int[3], state.apu.env_delay), // clocks until next envelope action + LOAD(int[3], state.apu.env_volume), + LOAD(int[3], state.apu.env_enabled), - SKIP( int [13], room_for_expansion ), + SKIP(int[13], room_for_expansion), - // Emulator - SKIP( int [16], room_for_expansion ), + // Emulator + SKIP(int[16], room_for_expansion), - { NULL, 0 } + { NULL, 0 } }; -void gbSoundSaveGame( gzFile out ) +void gbSoundSaveGame(gzFile out) { - gb_apu->save_state( &state.apu ); + gb_apu->save_state(&state.apu); - // Be sure areas for expansion get written as zero - memset( dummy_state, 0, sizeof dummy_state ); + // Be sure areas for expansion get written as zero + memset(dummy_state, 0, sizeof dummy_state); - state.version = 1; - utilWriteData( out, gb_state ); + state.version = 1; + utilWriteData(out, gb_state); } -void gbSoundReadGame( int version, gzFile in ) +void gbSoundReadGame(int version, gzFile in) { - // Prepare APU and default state - reset_apu(); - gb_apu->save_state( &state.apu ); + // Prepare APU and default state + reset_apu(); + gb_apu->save_state(&state.apu); - if ( version > 11 ) - utilReadData( in, gb_state ); - else - gbSoundReadGameOld( version, in ); + if (version > 11) + utilReadData(in, gb_state); + else + gbSoundReadGameOld(version, in); - gb_apu->load_state( state.apu ); + gb_apu->load_state(state.apu); } diff --git a/src/gb/gbSound.h b/src/gb/gbSound.h index 9272cb36..8aaca9ae 100644 --- a/src/gb/gbSound.h +++ b/src/gb/gbSound.h @@ -16,15 +16,15 @@ bool gbSoundGetDeclicking(); // Effects configuration struct gb_effects_config_t { - bool enabled; // false = disable all effects + bool enabled; // false = disable all effects - float echo; // 0.0 = none, 1.0 = lots - float stereo; // 0.0 = channels in center, 1.0 = channels on left/right - bool surround; // true = put some channels in back + float echo; // 0.0 = none, 1.0 = lots + float stereo; // 0.0 = channels in center, 1.0 = channels on left/right + bool surround; // true = put some channels in back }; // Changes effects configuration -void gbSoundConfigEffects(gb_effects_config_t const &); +void gbSoundConfigEffects(gb_effects_config_t const&); extern gb_effects_config_t gb_effects_config; // current configuration //// GB sound emulation @@ -65,7 +65,7 @@ u8 gbSoundRead(u16 address); // Notifies emulator that SOUND_CLOCK_TICKS clocks have passed void gbSoundTick(); extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to gbSoundTick() -extern int soundTicks; // Number of 16.8 MHz clocks until gbSoundTick() will be called +extern int soundTicks; // Number of 16.8 MHz clocks until gbSoundTick() will be called // Saves/loads emulator state void gbSoundSaveGame(gzFile out);