annotate src/gb/GB.cpp @ 50:e643f55bc886

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