annotate src/gb/GB.cpp @ 24:59790d015f25 works-incomplete

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