annotate src/gb/GB.cpp @ 68:86093f2ce7d1

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