annotate src/gba/GBA.cpp @ 24:59790d015f25 works-incomplete

checkpoint
author Robert McIntyre <rlm@mit.edu>
date Sun, 04 Mar 2012 17:50:56 -0600
parents f9f4f1b99eed
children
rev   line source
rlm@1 1 #include <cstdio>
rlm@1 2 #include <cstdlib>
rlm@1 3 #include <cstdarg>
rlm@1 4 #include <cstring>
rlm@1 5
rlm@1 6 #include "../Port.h"
rlm@1 7 #include "../NLS.h"
rlm@1 8 #include "GBA.h"
rlm@1 9 //#include "GBAGlobals.h"
rlm@1 10 #include "GBACheats.h" // FIXME: SDL requires this included before "GBAinline.h"
rlm@1 11 #include "GBAinline.h"
rlm@1 12 #include "GBAGfx.h"
rlm@1 13 #include "GBASound.h"
rlm@1 14 #include "EEprom.h"
rlm@1 15 #include "Flash.h"
rlm@1 16 #include "Sram.h"
rlm@1 17 #include "bios.h"
rlm@1 18 #include "elf.h"
rlm@1 19 #include "agbprint.h"
rlm@1 20 #include "../common/unzip.h"
rlm@1 21 #include "../common/Util.h"
rlm@1 22 #include "../common/movie.h"
rlm@1 23 #include "../common/vbalua.h"
rlm@1 24
rlm@1 25 #ifdef PROFILING
rlm@1 26 #include "../prof/prof.h"
rlm@1 27 #endif
rlm@1 28
rlm@1 29 #define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]), value)
rlm@1 30
rlm@1 31 #ifdef __GNUC__
rlm@1 32 #define _stricmp strcasecmp
rlm@1 33 #endif
rlm@1 34
rlm@1 35 #define CPU_BREAK_LOOP \
rlm@1 36 cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \
rlm@1 37 *extCpuLoopTicks = *extClockTicks;
rlm@1 38
rlm@1 39 #define CPU_BREAK_LOOP_2 \
rlm@1 40 cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \
rlm@1 41 *extCpuLoopTicks = *extClockTicks; \
rlm@1 42 *extTicks = *extClockTicks;
rlm@1 43
rlm@1 44 int32 cpuDmaTicksToUpdate = 0;
rlm@1 45 int32 cpuDmaCount = 0;
rlm@1 46 bool8 cpuDmaHack = 0;
rlm@1 47 u32 cpuDmaLast = 0;
rlm@1 48 int32 dummyAddress = 0;
rlm@1 49
rlm@1 50 int32 *extCpuLoopTicks = NULL;
rlm@1 51 int32 *extClockTicks = NULL;
rlm@1 52 int32 *extTicks = NULL;
rlm@1 53
rlm@1 54 #if (defined(WIN32) && !defined(SDL))
rlm@1 55 HANDLE mapROM; // shared memory handles
rlm@1 56 HANDLE mapWORKRAM;
rlm@1 57 HANDLE mapBIOS;
rlm@1 58 HANDLE mapIRAM;
rlm@1 59 HANDLE mapPALETTERAM;
rlm@1 60 HANDLE mapVRAM;
rlm@1 61 HANDLE mapOAM;
rlm@1 62 HANDLE mapPIX;
rlm@1 63 HANDLE mapIOMEM;
rlm@1 64 #endif
rlm@1 65
rlm@1 66 int32 gbaSaveType = 0; // used to remember the save type on reset
rlm@1 67 bool8 intState = false;
rlm@1 68 bool8 stopState = false;
rlm@1 69 bool8 holdState = false;
rlm@1 70 int32 holdType = 0;
rlm@1 71 bool8 cpuSramEnabled = true;
rlm@1 72 bool8 cpuFlashEnabled = true;
rlm@1 73 bool8 cpuEEPROMEnabled = true;
rlm@1 74 bool8 cpuEEPROMSensorEnabled = false;
rlm@1 75
rlm@1 76 #ifdef PROFILING
rlm@1 77 int profilingTicks = 0;
rlm@1 78 int profilingTicksReload = 0;
rlm@1 79 static char *profilBuffer = NULL;
rlm@1 80 static int profilSize = 0;
rlm@1 81 static u32 profilLowPC = 0;
rlm@1 82 static int profilScale = 0;
rlm@1 83 #endif
rlm@1 84 bool8 freezeWorkRAM[0x40000];
rlm@1 85 bool8 freezeInternalRAM[0x8000];
rlm@1 86 int32 lcdTicks = 960;
rlm@1 87 bool8 timer0On = false;
rlm@1 88 int32 timer0Ticks = 0;
rlm@1 89 int32 timer0Reload = 0;
rlm@1 90 int32 timer0ClockReload = 0;
rlm@1 91 bool8 timer1On = false;
rlm@1 92 int32 timer1Ticks = 0;
rlm@1 93 int32 timer1Reload = 0;
rlm@1 94 int32 timer1ClockReload = 0;
rlm@1 95 bool8 timer2On = false;
rlm@1 96 int32 timer2Ticks = 0;
rlm@1 97 int32 timer2Reload = 0;
rlm@1 98 int32 timer2ClockReload = 0;
rlm@1 99 bool8 timer3On = false;
rlm@1 100 int32 timer3Ticks = 0;
rlm@1 101 int32 timer3Reload = 0;
rlm@1 102 int32 timer3ClockReload = 0;
rlm@1 103 u32 dma0Source = 0;
rlm@1 104 u32 dma0Dest = 0;
rlm@1 105 u32 dma1Source = 0;
rlm@1 106 u32 dma1Dest = 0;
rlm@1 107 u32 dma2Source = 0;
rlm@1 108 u32 dma2Dest = 0;
rlm@1 109 u32 dma3Source = 0;
rlm@1 110 u32 dma3Dest = 0;
rlm@1 111 void (*cpuSaveGameFunc)(u32, u8) = flashSaveDecide;
rlm@1 112 void (*renderLine)() = mode0RenderLine;
rlm@1 113 bool8 fxOn = false;
rlm@1 114 bool8 windowOn = false;
rlm@1 115 int32 frameSkipCount = 0;
rlm@1 116 u32 gbaLastTime = 0;
rlm@1 117 int32 gbaFrameCount = 0;
rlm@1 118 bool8 prefetchActive = false, prefetchPrevActive = false, prefetchApplies = false;
rlm@1 119 char buffer[1024];
rlm@1 120 FILE *out = NULL;
rlm@1 121
rlm@1 122 static bool newFrame = true;
rlm@1 123 static bool pauseAfterFrameAdvance = false;
rlm@1 124
rlm@1 125 const int32 TIMER_TICKS[4] = {
rlm@1 126 1,
rlm@1 127 64,
rlm@1 128 256,
rlm@1 129 1024
rlm@1 130 };
rlm@1 131
rlm@1 132 const int32 thumbCycles[] = {
rlm@1 133 // 0 1 2 3 4 5 6 7 8 9 a b c d e f
rlm@1 134 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
rlm@1 135 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
rlm@1 136 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
rlm@1 137 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
rlm@1 138 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4
rlm@1 139 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5
rlm@1 140 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6
rlm@1 141 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7
rlm@1 142 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8
rlm@1 143 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9
rlm@1 144 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a
rlm@1 145 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b
rlm@1 146 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c
rlm@1 147 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d
rlm@1 148 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e
rlm@1 149 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f
rlm@1 150 };
rlm@1 151
rlm@1 152 const int32 gamepakRamWaitState[4] = { 4, 3, 2, 8 };
rlm@1 153 const int32 gamepakWaitState[8] = { 4, 3, 2, 8, 4, 3, 2, 8 };
rlm@1 154 const int32 gamepakWaitState0[8] = { 2, 2, 2, 2, 1, 1, 1, 1 };
rlm@1 155 const int32 gamepakWaitState1[8] = { 4, 4, 4, 4, 1, 1, 1, 1 };
rlm@1 156 const int32 gamepakWaitState2[8] = { 8, 8, 8, 8, 1, 1, 1, 1 };
rlm@1 157
rlm@1 158 int32 memoryWait[16] =
rlm@1 159 { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
rlm@1 160 int32 memoryWait32[16] =
rlm@1 161 { 0, 0, 9, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
rlm@1 162 int32 memoryWaitSeq[16] =
rlm@1 163 { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 };
rlm@1 164 int32 memoryWaitSeq32[16] =
rlm@1 165 { 2, 0, 3, 0, 0, 2, 2, 0, 4, 4, 8, 8, 16, 16, 8, 0 };
rlm@1 166 int32 memoryWaitFetch[16] =
rlm@1 167 { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
rlm@1 168 int32 memoryWaitFetch32[16] =
rlm@1 169 { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
rlm@1 170
rlm@1 171 const int32 cpuMemoryWait[16] = {
rlm@1 172 0, 0, 2, 0, 0, 0, 0, 0,
rlm@1 173 2, 2, 2, 2, 2, 2, 0, 0
rlm@1 174 };
rlm@1 175 const int32 cpuMemoryWait32[16] = {
rlm@1 176 0, 0, 3, 0, 0, 0, 0, 0,
rlm@1 177 3, 3, 3, 3, 3, 3, 0, 0
rlm@1 178 };
rlm@1 179
rlm@1 180 const bool8 memory32[16] = {
rlm@1 181 true, false, false, true, true, false, false, true, false, false, false, false, false, false, true, false
rlm@1 182 };
rlm@1 183
rlm@1 184 u8 biosProtected[4];
rlm@1 185
rlm@1 186 u8 cpuBitsSet[256];
rlm@1 187 u8 cpuLowestBitSet[256];
rlm@1 188
rlm@1 189 #ifdef WORDS_BIGENDIAN
rlm@1 190 bool8 cpuBiosSwapped = false;
rlm@1 191 #endif
rlm@1 192
rlm@1 193 u32 myROM[] = {
rlm@1 194 0xEA000006,
rlm@1 195 0xEA000093,
rlm@1 196 0xEA000006,
rlm@1 197 0x00000000,
rlm@1 198 0x00000000,
rlm@1 199 0x00000000,
rlm@1 200 0xEA000088,
rlm@1 201 0x00000000,
rlm@1 202 0xE3A00302,
rlm@1 203 0xE1A0F000,
rlm@1 204 0xE92D5800,
rlm@1 205 0xE55EC002,
rlm@1 206 0xE28FB03C,
rlm@1 207 0xE79BC10C,
rlm@1 208 0xE14FB000,
rlm@1 209 0xE92D0800,
rlm@1 210 0xE20BB080,
rlm@1 211 0xE38BB01F,
rlm@1 212 0xE129F00B,
rlm@1 213 0xE92D4004,
rlm@1 214 0xE1A0E00F,
rlm@1 215 0xE12FFF1C,
rlm@1 216 0xE8BD4004,
rlm@1 217 0xE3A0C0D3,
rlm@1 218 0xE129F00C,
rlm@1 219 0xE8BD0800,
rlm@1 220 0xE169F00B,
rlm@1 221 0xE8BD5800,
rlm@1 222 0xE1B0F00E,
rlm@1 223 0x0000009C,
rlm@1 224 0x0000009C,
rlm@1 225 0x0000009C,
rlm@1 226 0x0000009C,
rlm@1 227 0x000001F8,
rlm@1 228 0x000001F0,
rlm@1 229 0x000000AC,
rlm@1 230 0x000000A0,
rlm@1 231 0x000000FC,
rlm@1 232 0x00000168,
rlm@1 233 0xE12FFF1E,
rlm@1 234 0xE1A03000,
rlm@1 235 0xE1A00001,
rlm@1 236 0xE1A01003,
rlm@1 237 0xE2113102,
rlm@1 238 0x42611000,
rlm@1 239 0xE033C040,
rlm@1 240 0x22600000,
rlm@1 241 0xE1B02001,
rlm@1 242 0xE15200A0,
rlm@1 243 0x91A02082,
rlm@1 244 0x3AFFFFFC,
rlm@1 245 0xE1500002,
rlm@1 246 0xE0A33003,
rlm@1 247 0x20400002,
rlm@1 248 0xE1320001,
rlm@1 249 0x11A020A2,
rlm@1 250 0x1AFFFFF9,
rlm@1 251 0xE1A01000,
rlm@1 252 0xE1A00003,
rlm@1 253 0xE1B0C08C,
rlm@1 254 0x22600000,
rlm@1 255 0x42611000,
rlm@1 256 0xE12FFF1E,
rlm@1 257 0xE92D0010,
rlm@1 258 0xE1A0C000,
rlm@1 259 0xE3A01001,
rlm@1 260 0xE1500001,
rlm@1 261 0x81A000A0,
rlm@1 262 0x81A01081,
rlm@1 263 0x8AFFFFFB,
rlm@1 264 0xE1A0000C,
rlm@1 265 0xE1A04001,
rlm@1 266 0xE3A03000,
rlm@1 267 0xE1A02001,
rlm@1 268 0xE15200A0,
rlm@1 269 0x91A02082,
rlm@1 270 0x3AFFFFFC,
rlm@1 271 0xE1500002,
rlm@1 272 0xE0A33003,
rlm@1 273 0x20400002,
rlm@1 274 0xE1320001,
rlm@1 275 0x11A020A2,
rlm@1 276 0x1AFFFFF9,
rlm@1 277 0xE0811003,
rlm@1 278 0xE1B010A1,
rlm@1 279 0xE1510004,
rlm@1 280 0x3AFFFFEE,
rlm@1 281 0xE1A00004,
rlm@1 282 0xE8BD0010,
rlm@1 283 0xE12FFF1E,
rlm@1 284 0xE0010090,
rlm@1 285 0xE1A01741,
rlm@1 286 0xE2611000,
rlm@1 287 0xE3A030A9,
rlm@1 288 0xE0030391,
rlm@1 289 0xE1A03743,
rlm@1 290 0xE2833E39,
rlm@1 291 0xE0030391,
rlm@1 292 0xE1A03743,
rlm@1 293 0xE2833C09,
rlm@1 294 0xE283301C,
rlm@1 295 0xE0030391,
rlm@1 296 0xE1A03743,
rlm@1 297 0xE2833C0F,
rlm@1 298 0xE28330B6,
rlm@1 299 0xE0030391,
rlm@1 300 0xE1A03743,
rlm@1 301 0xE2833C16,
rlm@1 302 0xE28330AA,
rlm@1 303 0xE0030391,
rlm@1 304 0xE1A03743,
rlm@1 305 0xE2833A02,
rlm@1 306 0xE2833081,
rlm@1 307 0xE0030391,
rlm@1 308 0xE1A03743,
rlm@1 309 0xE2833C36,
rlm@1 310 0xE2833051,
rlm@1 311 0xE0030391,
rlm@1 312 0xE1A03743,
rlm@1 313 0xE2833CA2,
rlm@1 314 0xE28330F9,
rlm@1 315 0xE0000093,
rlm@1 316 0xE1A00840,
rlm@1 317 0xE12FFF1E,
rlm@1 318 0xE3A00001,
rlm@1 319 0xE3A01001,
rlm@1 320 0xE92D4010,
rlm@1 321 0xE3A0C301,
rlm@1 322 0xE3A03000,
rlm@1 323 0xE3A04001,
rlm@1 324 0xE3500000,
rlm@1 325 0x1B000004,
rlm@1 326 0xE5CC3301,
rlm@1 327 0xEB000002,
rlm@1 328 0x0AFFFFFC,
rlm@1 329 0xE8BD4010,
rlm@1 330 0xE12FFF1E,
rlm@1 331 0xE5CC3208,
rlm@1 332 0xE15C20B8,
rlm@1 333 0xE0110002,
rlm@1 334 0x10200002,
rlm@1 335 0x114C00B8,
rlm@1 336 0xE5CC4208,
rlm@1 337 0xE12FFF1E,
rlm@1 338 0xE92D500F,
rlm@1 339 0xE3A00301,
rlm@1 340 0xE1A0E00F,
rlm@1 341 0xE510F004,
rlm@1 342 0xE8BD500F,
rlm@1 343 0xE25EF004,
rlm@1 344 0xE59FD044,
rlm@1 345 0xE92D5000,
rlm@1 346 0xE14FC000,
rlm@1 347 0xE10FE000,
rlm@1 348 0xE92D5000,
rlm@1 349 0xE3A0C302,
rlm@1 350 0xE5DCE09C,
rlm@1 351 0xE35E00A5,
rlm@1 352 0x1A000004,
rlm@1 353 0x05DCE0B4,
rlm@1 354 0x021EE080,
rlm@1 355 0xE28FE004,
rlm@1 356 0x159FF018,
rlm@1 357 0x059FF018,
rlm@1 358 0xE59FD018,
rlm@1 359 0xE8BD5000,
rlm@1 360 0xE169F00C,
rlm@1 361 0xE8BD5000,
rlm@1 362 0xE25EF004,
rlm@1 363 0x03007FF0,
rlm@1 364 0x09FE2000,
rlm@1 365 0x09FFC000,
rlm@1 366 0x03007FE0
rlm@1 367 };
rlm@1 368
rlm@1 369 variable_desc saveGameStruct[] = {
rlm@1 370 { &DISPCNT, sizeof(u16) },
rlm@1 371 { &DISPSTAT, sizeof(u16) },
rlm@1 372 { &VCOUNT, sizeof(u16) },
rlm@1 373 { &BG0CNT, sizeof(u16) },
rlm@1 374 { &BG1CNT, sizeof(u16) },
rlm@1 375 { &BG2CNT, sizeof(u16) },
rlm@1 376 { &BG3CNT, sizeof(u16) },
rlm@1 377 { &BG0HOFS, sizeof(u16) },
rlm@1 378 { &BG0VOFS, sizeof(u16) },
rlm@1 379 { &BG1HOFS, sizeof(u16) },
rlm@1 380 { &BG1VOFS, sizeof(u16) },
rlm@1 381 { &BG2HOFS, sizeof(u16) },
rlm@1 382 { &BG2VOFS, sizeof(u16) },
rlm@1 383 { &BG3HOFS, sizeof(u16) },
rlm@1 384 { &BG3VOFS, sizeof(u16) },
rlm@1 385 { &BG2PA, sizeof(u16) },
rlm@1 386 { &BG2PB, sizeof(u16) },
rlm@1 387 { &BG2PC, sizeof(u16) },
rlm@1 388 { &BG2PD, sizeof(u16) },
rlm@1 389 { &BG2X_L, sizeof(u16) },
rlm@1 390 { &BG2X_H, sizeof(u16) },
rlm@1 391 { &BG2Y_L, sizeof(u16) },
rlm@1 392 { &BG2Y_H, sizeof(u16) },
rlm@1 393 { &BG3PA, sizeof(u16) },
rlm@1 394 { &BG3PB, sizeof(u16) },
rlm@1 395 { &BG3PC, sizeof(u16) },
rlm@1 396 { &BG3PD, sizeof(u16) },
rlm@1 397 { &BG3X_L, sizeof(u16) },
rlm@1 398 { &BG3X_H, sizeof(u16) },
rlm@1 399 { &BG3Y_L, sizeof(u16) },
rlm@1 400 { &BG3Y_H, sizeof(u16) },
rlm@1 401 { &WIN0H, sizeof(u16) },
rlm@1 402 { &WIN1H, sizeof(u16) },
rlm@1 403 { &WIN0V, sizeof(u16) },
rlm@1 404 { &WIN1V, sizeof(u16) },
rlm@1 405 { &WININ, sizeof(u16) },
rlm@1 406 { &WINOUT, sizeof(u16) },
rlm@1 407 { &MOSAIC, sizeof(u16) },
rlm@1 408 { &BLDMOD, sizeof(u16) },
rlm@1 409 { &COLEV, sizeof(u16) },
rlm@1 410 { &COLY, sizeof(u16) },
rlm@1 411 { &DM0SAD_L, sizeof(u16) },
rlm@1 412 { &DM0SAD_H, sizeof(u16) },
rlm@1 413 { &DM0DAD_L, sizeof(u16) },
rlm@1 414 { &DM0DAD_H, sizeof(u16) },
rlm@1 415 { &DM0CNT_L, sizeof(u16) },
rlm@1 416 { &DM0CNT_H, sizeof(u16) },
rlm@1 417 { &DM1SAD_L, sizeof(u16) },
rlm@1 418 { &DM1SAD_H, sizeof(u16) },
rlm@1 419 { &DM1DAD_L, sizeof(u16) },
rlm@1 420 { &DM1DAD_H, sizeof(u16) },
rlm@1 421 { &DM1CNT_L, sizeof(u16) },
rlm@1 422 { &DM1CNT_H, sizeof(u16) },
rlm@1 423 { &DM2SAD_L, sizeof(u16) },
rlm@1 424 { &DM2SAD_H, sizeof(u16) },
rlm@1 425 { &DM2DAD_L, sizeof(u16) },
rlm@1 426 { &DM2DAD_H, sizeof(u16) },
rlm@1 427 { &DM2CNT_L, sizeof(u16) },
rlm@1 428 { &DM2CNT_H, sizeof(u16) },
rlm@1 429 { &DM3SAD_L, sizeof(u16) },
rlm@1 430 { &DM3SAD_H, sizeof(u16) },
rlm@1 431 { &DM3DAD_L, sizeof(u16) },
rlm@1 432 { &DM3DAD_H, sizeof(u16) },
rlm@1 433 { &DM3CNT_L, sizeof(u16) },
rlm@1 434 { &DM3CNT_H, sizeof(u16) },
rlm@1 435 { &TM0D, sizeof(u16) },
rlm@1 436 { &TM0CNT, sizeof(u16) },
rlm@1 437 { &TM1D, sizeof(u16) },
rlm@1 438 { &TM1CNT, sizeof(u16) },
rlm@1 439 { &TM2D, sizeof(u16) },
rlm@1 440 { &TM2CNT, sizeof(u16) },
rlm@1 441 { &TM3D, sizeof(u16) },
rlm@1 442 { &TM3CNT, sizeof(u16) },
rlm@1 443 { &P1, sizeof(u16) },
rlm@1 444 { &IE, sizeof(u16) },
rlm@1 445 { &IF, sizeof(u16) },
rlm@1 446 { &IME, sizeof(u16) },
rlm@1 447 { &holdState, sizeof(bool8) },
rlm@1 448 { &holdType, sizeof(int32) },
rlm@1 449 { &lcdTicks, sizeof(int32) },
rlm@1 450 { &timer0On, sizeof(bool8) },
rlm@1 451 { &timer0Ticks, sizeof(int32) },
rlm@1 452 { &timer0Reload, sizeof(int32) },
rlm@1 453 { &timer0ClockReload, sizeof(int32) },
rlm@1 454 { &timer1On, sizeof(bool8) },
rlm@1 455 { &timer1Ticks, sizeof(int32) },
rlm@1 456 { &timer1Reload, sizeof(int32) },
rlm@1 457 { &timer1ClockReload, sizeof(int32) },
rlm@1 458 { &timer2On, sizeof(bool8) },
rlm@1 459 { &timer2Ticks, sizeof(int32) },
rlm@1 460 { &timer2Reload, sizeof(int32) },
rlm@1 461 { &timer2ClockReload, sizeof(int32) },
rlm@1 462 { &timer3On, sizeof(bool8) },
rlm@1 463 { &timer3Ticks, sizeof(int32) },
rlm@1 464 { &timer3Reload, sizeof(int32) },
rlm@1 465 { &timer3ClockReload, sizeof(int32) },
rlm@1 466 { &dma0Source, sizeof(u32) },
rlm@1 467 { &dma0Dest, sizeof(u32) },
rlm@1 468 { &dma1Source, sizeof(u32) },
rlm@1 469 { &dma1Dest, sizeof(u32) },
rlm@1 470 { &dma2Source, sizeof(u32) },
rlm@1 471 { &dma2Dest, sizeof(u32) },
rlm@1 472 { &dma3Source, sizeof(u32) },
rlm@1 473 { &dma3Dest, sizeof(u32) },
rlm@1 474 { &fxOn, sizeof(bool8) },
rlm@1 475 { &windowOn, sizeof(bool8) },
rlm@1 476 { &N_FLAG, sizeof(bool8) },
rlm@1 477 { &C_FLAG, sizeof(bool8) },
rlm@1 478 { &Z_FLAG, sizeof(bool8) },
rlm@1 479 { &V_FLAG, sizeof(bool8) },
rlm@1 480 { &armState, sizeof(bool8) },
rlm@1 481 { &armIrqEnable, sizeof(bool8) },
rlm@1 482 { &armNextPC, sizeof(u32) },
rlm@1 483 { &armMode, sizeof(int32) },
rlm@1 484 { &saveType, sizeof(int32) },
rlm@1 485 { NULL, 0 }
rlm@1 486 };
rlm@1 487
rlm@1 488 //int cpuLoopTicks = 0;
rlm@1 489 int cpuSavedTicks = 0;
rlm@1 490
rlm@1 491 #ifdef PROFILING
rlm@1 492 void cpuProfil(char *buf, int size, u32 lowPC, int scale)
rlm@1 493 {
rlm@1 494 profilBuffer = buf;
rlm@1 495 profilSize = size;
rlm@1 496 profilLowPC = lowPC;
rlm@1 497 profilScale = scale;
rlm@1 498 }
rlm@1 499
rlm@1 500 void cpuEnableProfiling(int hz)
rlm@1 501 {
rlm@1 502 if (hz == 0)
rlm@1 503 hz = 100;
rlm@1 504 profilingTicks = profilingTicksReload = 16777216 / hz;
rlm@1 505 profSetHertz(hz);
rlm@1 506 }
rlm@1 507
rlm@1 508 #endif
rlm@1 509
rlm@1 510 inline int CPUUpdateTicksAccess32(u32 address)
rlm@1 511 {
rlm@1 512 return memoryWait32[(address >> 24) & 15];
rlm@1 513 }
rlm@1 514
rlm@1 515 inline int CPUUpdateTicksAccess16(u32 address)
rlm@1 516 {
rlm@1 517 return memoryWait[(address >> 24) & 15];
rlm@1 518 }
rlm@1 519
rlm@1 520 inline int CPUUpdateTicksAccessSeq32(u32 address)
rlm@1 521 {
rlm@1 522 return memoryWaitSeq32[(address >> 24) & 15];
rlm@1 523 }
rlm@1 524
rlm@1 525 inline int CPUUpdateTicksAccessSeq16(u32 address)
rlm@1 526 {
rlm@1 527 return memoryWaitSeq[(address >> 24) & 15];
rlm@1 528 }
rlm@1 529
rlm@1 530 inline int CPUUpdateTicks()
rlm@1 531 {
rlm@1 532 int cpuLoopTicks = lcdTicks;
rlm@1 533
rlm@1 534 if (soundTicks < cpuLoopTicks)
rlm@1 535 cpuLoopTicks = soundTicks;
rlm@1 536
rlm@1 537 if (timer0On && !(TM0CNT & 4) && (timer0Ticks < cpuLoopTicks))
rlm@1 538 {
rlm@1 539 cpuLoopTicks = timer0Ticks;
rlm@1 540 }
rlm@1 541 if (timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks))
rlm@1 542 {
rlm@1 543 cpuLoopTicks = timer1Ticks;
rlm@1 544 }
rlm@1 545 if (timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks))
rlm@1 546 {
rlm@1 547 cpuLoopTicks = timer2Ticks;
rlm@1 548 }
rlm@1 549 if (timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks))
rlm@1 550 {
rlm@1 551 cpuLoopTicks = timer3Ticks;
rlm@1 552 }
rlm@1 553 #ifdef PROFILING
rlm@1 554 if (profilingTicksReload != 0)
rlm@1 555 {
rlm@1 556 if (profilingTicks < cpuLoopTicks)
rlm@1 557 {
rlm@1 558 cpuLoopTicks = profilingTicks;
rlm@1 559 }
rlm@1 560 }
rlm@1 561 #endif
rlm@1 562 cpuSavedTicks = cpuLoopTicks;
rlm@1 563 return cpuLoopTicks;
rlm@1 564 }
rlm@1 565
rlm@1 566 void CPUUpdateWindow0()
rlm@1 567 {
rlm@1 568 int x00 = WIN0H >> 8;
rlm@1 569 int x01 = WIN0H & 255;
rlm@1 570
rlm@1 571 if (x00 <= x01)
rlm@1 572 {
rlm@1 573 for (int i = 0; i < 240; i++)
rlm@1 574 {
rlm@1 575 gfxInWin0[i] = (i >= x00 && i < x01);
rlm@1 576 }
rlm@1 577 }
rlm@1 578 else
rlm@1 579 {
rlm@1 580 for (int i = 0; i < 240; i++)
rlm@1 581 {
rlm@1 582 gfxInWin0[i] = (i >= x00 || i < x01);
rlm@1 583 }
rlm@1 584 }
rlm@1 585 }
rlm@1 586
rlm@1 587 void CPUUpdateWindow1()
rlm@1 588 {
rlm@1 589 int x00 = WIN1H >> 8;
rlm@1 590 int x01 = WIN1H & 255;
rlm@1 591
rlm@1 592 if (x00 <= x01)
rlm@1 593 {
rlm@1 594 for (int i = 0; i < 240; i++)
rlm@1 595 {
rlm@1 596 gfxInWin1[i] = (i >= x00 && i < x01);
rlm@1 597 }
rlm@1 598 }
rlm@1 599 else
rlm@1 600 {
rlm@1 601 for (int i = 0; i < 240; i++)
rlm@1 602 {
rlm@1 603 gfxInWin1[i] = (i >= x00 || i < x01);
rlm@1 604 }
rlm@1 605 }
rlm@1 606 }
rlm@1 607
rlm@1 608 #define CLEAR_ARRAY(a) \
rlm@1 609 { \
rlm@1 610 u32 *array = (a); \
rlm@1 611 for (int i = 0; i < 240; i++) { \
rlm@1 612 *array++ = 0x80000000; \
rlm@1 613 } \
rlm@1 614 } \
rlm@1 615
rlm@1 616 void CPUUpdateRenderBuffers(bool force)
rlm@1 617 {
rlm@1 618 if (!(layerEnable & 0x0100) || force)
rlm@1 619 {
rlm@1 620 CLEAR_ARRAY(line0);
rlm@1 621 }
rlm@1 622 if (!(layerEnable & 0x0200) || force)
rlm@1 623 {
rlm@1 624 CLEAR_ARRAY(line1);
rlm@1 625 }
rlm@1 626 if (!(layerEnable & 0x0400) || force)
rlm@1 627 {
rlm@1 628 CLEAR_ARRAY(line2);
rlm@1 629 }
rlm@1 630 if (!(layerEnable & 0x0800) || force)
rlm@1 631 {
rlm@1 632 CLEAR_ARRAY(line3);
rlm@1 633 }
rlm@1 634 }
rlm@1 635
rlm@1 636 bool CPUWriteStateToStream(gzFile gzFile)
rlm@1 637 {
rlm@1 638 utilWriteInt(gzFile, SAVE_GAME_VERSION);
rlm@1 639
rlm@1 640 utilGzWrite(gzFile, &rom[0xa0], 16);
rlm@1 641
rlm@1 642 utilWriteInt(gzFile, useBios);
rlm@1 643
rlm@1 644 utilGzWrite(gzFile, &reg[0], sizeof(reg));
rlm@1 645
rlm@1 646 utilWriteData(gzFile, saveGameStruct);
rlm@1 647
rlm@1 648 // new to version 0.7.1
rlm@1 649 utilWriteInt(gzFile, stopState);
rlm@1 650 // new to version 0.8
rlm@1 651 utilWriteInt(gzFile, intState);
rlm@1 652
rlm@1 653 utilGzWrite(gzFile, internalRAM, 0x8000);
rlm@1 654 utilGzWrite(gzFile, paletteRAM, 0x400);
rlm@1 655 utilGzWrite(gzFile, workRAM, 0x40000);
rlm@1 656 utilGzWrite(gzFile, vram, 0x20000);
rlm@1 657 utilGzWrite(gzFile, oam, 0x400);
rlm@1 658 utilGzWrite(gzFile, pix, 4 * 241 * 162);
rlm@1 659 utilGzWrite(gzFile, ioMem, 0x400);
rlm@1 660
rlm@1 661 eepromSaveGame(gzFile);
rlm@1 662 flashSaveGame(gzFile);
rlm@1 663 soundSaveGame(gzFile);
rlm@1 664
rlm@1 665 cheatsSaveGame(gzFile);
rlm@1 666
rlm@1 667 // version 1.5
rlm@1 668 rtcSaveGame(gzFile);
rlm@1 669
rlm@1 670 // SAVE_GAME_VERSION_9 (new to re-recording version which is based on 1.72)
rlm@1 671 {
rlm@1 672 extern int32 sensorX, sensorY; // from SDL.cpp
rlm@1 673 utilGzWrite(gzFile, &sensorX, sizeof(sensorX));
rlm@1 674 utilGzWrite(gzFile, &sensorY, sizeof(sensorY));
rlm@1 675 bool8 movieActive = VBAMovieActive();
rlm@1 676 utilGzWrite(gzFile, &movieActive, sizeof(movieActive));
rlm@1 677 if (movieActive)
rlm@1 678 {
rlm@1 679 uint8 *movie_freeze_buf = NULL;
rlm@1 680 uint32 movie_freeze_size = 0;
rlm@1 681
rlm@1 682 VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size);
rlm@1 683 if (movie_freeze_buf)
rlm@1 684 {
rlm@1 685 utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size));
rlm@1 686 utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size);
rlm@1 687 delete [] movie_freeze_buf;
rlm@1 688 }
rlm@1 689 else
rlm@1 690 {
rlm@1 691 systemMessage(0, N_("Failed to save movie snapshot."));
rlm@1 692 return false;
rlm@1 693 }
rlm@1 694 }
rlm@1 695 utilGzWrite(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount));
rlm@1 696 }
rlm@1 697
rlm@1 698 // SAVE_GAME_VERSION_10
rlm@1 699 {
rlm@1 700 utilGzWrite(gzFile, memoryWait, 16 * sizeof(int32));
rlm@1 701 utilGzWrite(gzFile, memoryWait32, 16 * sizeof(int32));
rlm@1 702 utilGzWrite(gzFile, memoryWaitSeq, 16 * sizeof(int32));
rlm@1 703 utilGzWrite(gzFile, memoryWaitSeq32, 16 * sizeof(int32));
rlm@1 704 utilGzWrite(gzFile, memoryWaitFetch, 16 * sizeof(int32));
rlm@1 705 utilGzWrite(gzFile, memoryWaitFetch32, 16 * sizeof(int32));
rlm@1 706 }
rlm@1 707
rlm@1 708 // SAVE_GAME_VERSION_11
rlm@1 709 {
rlm@1 710 utilGzWrite(gzFile, &prefetchActive, sizeof(bool8));
rlm@1 711 utilGzWrite(gzFile, &prefetchPrevActive, sizeof(bool8));
rlm@1 712 utilGzWrite(gzFile, &prefetchApplies, sizeof(bool8));
rlm@1 713 }
rlm@1 714
rlm@1 715 // SAVE_GAME_VERSION_12
rlm@1 716 {
rlm@1 717 utilGzWrite(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary
rlm@1 718 utilGzWrite(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used...
rlm@1 719 }
rlm@1 720
rlm@1 721 // SAVE_GAME_VERSION_13
rlm@1 722 {
rlm@1 723 utilGzWrite(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount));
rlm@1 724 utilGzWrite(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged));
rlm@1 725 utilGzWrite(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast));
rlm@1 726 }
rlm@1 727
rlm@1 728 return true;
rlm@1 729 }
rlm@1 730
rlm@1 731 bool CPUWriteState(const char *file)
rlm@1 732 {
rlm@1 733 gzFile gzFile = utilGzOpen(file, "wb");
rlm@1 734
rlm@1 735 if (gzFile == NULL)
rlm@1 736 {
rlm@1 737 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file);
rlm@1 738 return false;
rlm@1 739 }
rlm@1 740
rlm@1 741 bool res = CPUWriteStateToStream(gzFile);
rlm@1 742
rlm@1 743 utilGzClose(gzFile);
rlm@1 744
rlm@1 745 return res;
rlm@1 746 }
rlm@1 747
rlm@1 748 bool CPUWriteMemState(char *memory, int available)
rlm@1 749 {
rlm@1 750 gzFile gzFile = utilMemGzOpen(memory, available, "w");
rlm@1 751
rlm@1 752 if (gzFile == NULL)
rlm@1 753 {
rlm@1 754 return false;
rlm@1 755 }
rlm@1 756
rlm@1 757 bool res = CPUWriteStateToStream(gzFile);
rlm@1 758
rlm@1 759 long pos = utilGzTell(gzFile) + 8;
rlm@1 760
rlm@1 761 if (pos >= (available))
rlm@1 762 res = false;
rlm@1 763
rlm@1 764 utilGzClose(gzFile);
rlm@1 765
rlm@1 766 return res;
rlm@1 767 }
rlm@1 768
rlm@1 769 static int tempStateID = 0;
rlm@1 770 static int tempFailCount = 0;
rlm@1 771 static bool backupSafe = true;
rlm@1 772
rlm@1 773 bool CPUReadStateFromStream(gzFile gzFile)
rlm@1 774 {
rlm@1 775 bool8 ub;
rlm@1 776 char tempBackupName [128];
rlm@1 777 if (backupSafe)
rlm@1 778 {
rlm@1 779 sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++);
rlm@1 780 CPUWriteState(tempBackupName);
rlm@1 781 }
rlm@1 782
rlm@1 783 int version = utilReadInt(gzFile);
rlm@1 784
rlm@1 785 if (version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1)
rlm@1 786 {
rlm@1 787 systemMessage(MSG_UNSUPPORTED_VBA_SGM,
rlm@1 788 N_("Unsupported VisualBoyAdvance save game version %d"),
rlm@1 789 version);
rlm@1 790 goto failedLoad;
rlm@1 791 }
rlm@1 792
rlm@1 793 u8 romname[17];
rlm@1 794
rlm@1 795 utilGzRead(gzFile, romname, 16);
rlm@1 796
rlm@1 797 if (memcmp(&rom[0xa0], romname, 16) != 0)
rlm@1 798 {
rlm@1 799 romname[16] = 0;
rlm@1 800 for (int i = 0; i < 16; i++)
rlm@1 801 if (romname[i] < 32)
rlm@1 802 romname[i] = 32;
rlm@1 803 systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname);
rlm@1 804 goto failedLoad;
rlm@1 805 }
rlm@1 806
rlm@1 807 ub = utilReadInt(gzFile) ? true : false;
rlm@1 808
rlm@1 809 if (ub != useBios)
rlm@1 810 {
rlm@1 811 if (useBios)
rlm@1 812 systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS,
rlm@1 813 N_("Save game is not using the BIOS files"));
rlm@1 814 else
rlm@1 815 systemMessage(MSG_SAVE_GAME_USING_BIOS,
rlm@1 816 N_("Save game is using the BIOS file"));
rlm@1 817 goto failedLoad;
rlm@1 818 }
rlm@1 819
rlm@1 820 utilGzRead(gzFile, &reg[0], sizeof(reg));
rlm@1 821
rlm@1 822 utilReadData(gzFile, saveGameStruct);
rlm@1 823
rlm@1 824 if (version < SAVE_GAME_VERSION_3)
rlm@1 825 stopState = false;
rlm@1 826 else
rlm@1 827 stopState = utilReadInt(gzFile) ? true : false;
rlm@1 828
rlm@1 829 if (version < SAVE_GAME_VERSION_4)
rlm@1 830 intState = false;
rlm@1 831 else
rlm@1 832 intState = utilReadInt(gzFile) ? true : false;
rlm@1 833
rlm@1 834 utilGzRead(gzFile, internalRAM, 0x8000);
rlm@1 835 utilGzRead(gzFile, paletteRAM, 0x400);
rlm@1 836 utilGzRead(gzFile, workRAM, 0x40000);
rlm@1 837 utilGzRead(gzFile, vram, 0x20000);
rlm@1 838 utilGzRead(gzFile, oam, 0x400);
rlm@1 839 if (version < SAVE_GAME_VERSION_6)
rlm@1 840 utilGzRead(gzFile, pix, 4 * 240 * 160);
rlm@1 841 else
rlm@1 842 utilGzRead(gzFile, pix, 4 * 241 * 162);
rlm@1 843 utilGzRead(gzFile, ioMem, 0x400);
rlm@1 844
rlm@1 845 eepromReadGame(gzFile, version);
rlm@1 846 flashReadGame(gzFile, version);
rlm@1 847 soundReadGame(gzFile, version);
rlm@1 848
rlm@1 849 if (version > SAVE_GAME_VERSION_1)
rlm@1 850 {
rlm@1 851 cheatsReadGame(gzFile);
rlm@1 852 }
rlm@1 853 if (version > SAVE_GAME_VERSION_6)
rlm@1 854 {
rlm@1 855 rtcReadGame(gzFile);
rlm@1 856 }
rlm@1 857
rlm@1 858 if (version <= SAVE_GAME_VERSION_7)
rlm@1 859 {
rlm@1 860 u32 temp;
rlm@1 861 #define SWAP(a, b, c) \
rlm@1 862 temp = (a); \
rlm@1 863 (a) = (b) << 16 | (c); \
rlm@1 864 (b) = (temp) >> 16; \
rlm@1 865 (c) = (temp) & 0xFFFF;
rlm@1 866
rlm@1 867 SWAP(dma0Source, DM0SAD_H, DM0SAD_L);
rlm@1 868 SWAP(dma0Dest, DM0DAD_H, DM0DAD_L);
rlm@1 869 SWAP(dma1Source, DM1SAD_H, DM1SAD_L);
rlm@1 870 SWAP(dma1Dest, DM1DAD_H, DM1DAD_L);
rlm@1 871 SWAP(dma2Source, DM2SAD_H, DM2SAD_L);
rlm@1 872 SWAP(dma2Dest, DM2DAD_H, DM2DAD_L);
rlm@1 873 SWAP(dma3Source, DM3SAD_H, DM3SAD_L);
rlm@1 874 SWAP(dma3Dest, DM3DAD_H, DM3DAD_L);
rlm@1 875 }
rlm@1 876
rlm@1 877 // set pointers!
rlm@1 878 layerEnable = layerSettings & DISPCNT;
rlm@1 879
rlm@1 880 CPUUpdateRender();
rlm@1 881 CPUUpdateRenderBuffers(true);
rlm@1 882 CPUUpdateWindow0();
rlm@1 883 CPUUpdateWindow1();
rlm@1 884 gbaSaveType = 0;
rlm@1 885 switch (saveType)
rlm@1 886 {
rlm@1 887 case 0:
rlm@1 888 cpuSaveGameFunc = flashSaveDecide;
rlm@1 889 break;
rlm@1 890 case 1:
rlm@1 891 cpuSaveGameFunc = sramWrite;
rlm@1 892 gbaSaveType = 1;
rlm@1 893 break;
rlm@1 894 case 2:
rlm@1 895 cpuSaveGameFunc = flashWrite;
rlm@1 896 gbaSaveType = 2;
rlm@1 897 break;
rlm@1 898 default:
rlm@1 899 systemMessage(MSG_UNSUPPORTED_SAVE_TYPE,
rlm@1 900 N_("Unsupported save type %d"), saveType);
rlm@1 901 break;
rlm@1 902 }
rlm@1 903 if (eepromInUse)
rlm@1 904 gbaSaveType = 3;
rlm@1 905
rlm@1 906 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
rlm@1 907
rlm@1 908 if (version >= SAVE_GAME_VERSION_9) // new to re-recording version:
rlm@1 909 {
rlm@1 910 extern int32 sensorX, sensorY; // from SDL.cpp
rlm@1 911 utilGzRead(gzFile, &sensorX, sizeof(sensorX));
rlm@1 912 utilGzRead(gzFile, &sensorY, sizeof(sensorY));
rlm@1 913
rlm@1 914 bool8 movieSnapshot;
rlm@1 915 utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot));
rlm@1 916 if (VBAMovieActive() && !movieSnapshot)
rlm@1 917 {
rlm@1 918 systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active."));
rlm@1 919 goto failedLoad;
rlm@1 920 }
rlm@1 921
rlm@1 922 if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added
rlm@1 923 // later on in the save format
rlm@1 924 {
rlm@1 925 uint32 movieInputDataSize = 0;
rlm@1 926 utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize));
rlm@1 927 uint8 *local_movie_data = new uint8[movieInputDataSize];
rlm@1 928 int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize);
rlm@1 929 if (readBytes != movieInputDataSize)
rlm@1 930 {
rlm@1 931 systemMessage(0, N_("Corrupt movie snapshot."));
rlm@1 932 if (local_movie_data)
rlm@1 933 delete [] local_movie_data;
rlm@1 934 goto failedLoad;
rlm@1 935 }
rlm@1 936 int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize);
rlm@1 937 if (local_movie_data)
rlm@1 938 delete [] local_movie_data;
rlm@1 939 if (code != MOVIE_SUCCESS && VBAMovieActive())
rlm@1 940 {
rlm@1 941 char errStr [1024];
rlm@1 942 strcpy(errStr, "Failed to load movie snapshot");
rlm@1 943 switch (code)
rlm@1 944 {
rlm@1 945 case MOVIE_NOT_FROM_THIS_MOVIE:
rlm@1 946 strcat(errStr, ";\nSnapshot not from this movie"); break;
rlm@1 947 case MOVIE_NOT_FROM_A_MOVIE:
rlm@1 948 strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here...
rlm@1 949 case MOVIE_SNAPSHOT_INCONSISTENT:
rlm@1 950 strcat(errStr, ";\nSnapshot inconsistent with movie"); break;
rlm@1 951 case MOVIE_WRONG_FORMAT:
rlm@1 952 strcat(errStr, ";\nWrong format"); break;
rlm@1 953 }
rlm@1 954 strcat(errStr, ".");
rlm@1 955 systemMessage(0, N_(errStr));
rlm@1 956 goto failedLoad;
rlm@1 957 }
rlm@1 958 }
rlm@1 959 utilGzRead(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount));
rlm@1 960 }
rlm@1 961 if (version >= SAVE_GAME_VERSION_10)
rlm@1 962 {
rlm@1 963 utilGzRead(gzFile, memoryWait, 16 * sizeof(int32));
rlm@1 964 utilGzRead(gzFile, memoryWait32, 16 * sizeof(int32));
rlm@1 965 utilGzRead(gzFile, memoryWaitSeq, 16 * sizeof(int32));
rlm@1 966 utilGzRead(gzFile, memoryWaitSeq32, 16 * sizeof(int32));
rlm@1 967 utilGzRead(gzFile, memoryWaitFetch, 16 * sizeof(int32));
rlm@1 968 utilGzRead(gzFile, memoryWaitFetch32, 16 * sizeof(int32));
rlm@1 969 }
rlm@1 970 if (version >= SAVE_GAME_VERSION_11)
rlm@1 971 {
rlm@1 972 utilGzRead(gzFile, &prefetchActive, sizeof(bool8));
rlm@1 973 //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
rlm@1 974 //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
rlm@1 975 utilGzRead(gzFile, &prefetchPrevActive, sizeof(bool8));
rlm@1 976 utilGzRead(gzFile, &prefetchApplies, sizeof(bool8));
rlm@1 977 }
rlm@1 978 if (version >= SAVE_GAME_VERSION_12)
rlm@1 979 {
rlm@1 980 utilGzRead(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary
rlm@1 981 utilGzRead(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used...
rlm@1 982 }
rlm@1 983 if (version >= SAVE_GAME_VERSION_13)
rlm@1 984 {
rlm@1 985 utilGzRead(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount));
rlm@1 986 utilGzRead(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged));
rlm@1 987 utilGzRead(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast));
rlm@1 988 }
rlm@1 989
rlm@1 990 if (backupSafe)
rlm@1 991 {
rlm@1 992 remove(tempBackupName);
rlm@1 993 tempFailCount = 0;
rlm@1 994 }
rlm@1 995 systemSetJoypad(0, ~P1 & 0x3FF);
rlm@1 996 VBAUpdateButtonPressDisplay();
rlm@1 997 VBAUpdateFrameCountDisplay();
rlm@1 998 systemRefreshScreen();
rlm@1 999 return true;
rlm@1 1000
rlm@1 1001 failedLoad:
rlm@1 1002 if (backupSafe)
rlm@1 1003 {
rlm@1 1004 tempFailCount++;
rlm@1 1005 if (tempFailCount < 3) // fail no more than 2 times in a row
rlm@1 1006 CPUReadState(tempBackupName);
rlm@1 1007 remove(tempBackupName);
rlm@1 1008 }
rlm@1 1009 return false;
rlm@1 1010 }
rlm@1 1011
rlm@1 1012 bool CPUReadMemState(char *memory, int available)
rlm@1 1013 {
rlm@1 1014 gzFile gzFile = utilMemGzOpen(memory, available, "r");
rlm@1 1015
rlm@1 1016 backupSafe = false;
rlm@1 1017 bool res = CPUReadStateFromStream(gzFile);
rlm@1 1018 backupSafe = true;
rlm@1 1019
rlm@1 1020 utilGzClose(gzFile);
rlm@1 1021
rlm@1 1022 return res;
rlm@1 1023 }
rlm@1 1024
rlm@1 1025 bool CPUReadState(const char *file)
rlm@1 1026 {
rlm@1 1027 gzFile gzFile = utilGzOpen(file, "rb");
rlm@1 1028
rlm@1 1029 if (gzFile == NULL)
rlm@1 1030 return false;
rlm@1 1031
rlm@1 1032 bool res = CPUReadStateFromStream(gzFile);
rlm@1 1033
rlm@1 1034 utilGzClose(gzFile);
rlm@1 1035
rlm@1 1036 return res;
rlm@1 1037 }
rlm@1 1038
rlm@1 1039 bool CPUExportEepromFile(const char *fileName)
rlm@1 1040 {
rlm@1 1041 if (eepromInUse)
rlm@1 1042 {
rlm@1 1043 FILE *file = fopen(fileName, "wb");
rlm@1 1044
rlm@1 1045 if (!file)
rlm@1 1046 {
rlm@1 1047 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
rlm@1 1048 fileName);
rlm@1 1049 return false;
rlm@1 1050 }
rlm@1 1051
rlm@1 1052 for (int i = 0; i < eepromSize; )
rlm@1 1053 {
rlm@1 1054 for (int j = 0; j < 8; j++)
rlm@1 1055 {
rlm@1 1056 if (fwrite(&eepromData[i + 7 - j], 1, 1, file) != 1)
rlm@1 1057 {
rlm@1 1058 fclose(file);
rlm@1 1059 return false;
rlm@1 1060 }
rlm@1 1061 }
rlm@1 1062 i += 8;
rlm@1 1063 }
rlm@1 1064 fclose(file);
rlm@1 1065 }
rlm@1 1066 return true;
rlm@1 1067 }
rlm@1 1068
rlm@1 1069 bool CPUWriteBatteryToStream(gzFile gzFile)
rlm@1 1070 {
rlm@1 1071 if (!gzFile)
rlm@1 1072 return false;
rlm@1 1073
rlm@1 1074 utilWriteInt(gzFile, SAVE_GAME_VERSION);
rlm@1 1075
rlm@1 1076 // for simplicity, we put both types of battery files should be in the stream, even if one's empty
rlm@1 1077 eepromSaveGame(gzFile);
rlm@1 1078 flashSaveGame(gzFile);
rlm@1 1079
rlm@1 1080 return true;
rlm@1 1081 }
rlm@1 1082
rlm@1 1083 bool CPUWriteBatteryFile(const char *fileName)
rlm@1 1084 {
rlm@1 1085 if (gbaSaveType == 0)
rlm@1 1086 {
rlm@1 1087 if (eepromInUse)
rlm@1 1088 gbaSaveType = 3;
rlm@1 1089 else
rlm@1 1090 switch (saveType)
rlm@1 1091 {
rlm@1 1092 case 1:
rlm@1 1093 gbaSaveType = 1;
rlm@1 1094 break;
rlm@1 1095 case 2:
rlm@1 1096 gbaSaveType = 2;
rlm@1 1097 break;
rlm@1 1098 }
rlm@1 1099 }
rlm@1 1100
rlm@1 1101 if (gbaSaveType)
rlm@1 1102 {
rlm@1 1103 FILE *file = fopen(fileName, "wb");
rlm@1 1104
rlm@1 1105 if (!file)
rlm@1 1106 {
rlm@1 1107 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
rlm@1 1108 fileName);
rlm@1 1109 return false;
rlm@1 1110 }
rlm@1 1111
rlm@1 1112 // only save if Flash/Sram in use or EEprom in use
rlm@1 1113 if (gbaSaveType != 3)
rlm@1 1114 {
rlm@1 1115 if (gbaSaveType == 2)
rlm@1 1116 {
rlm@1 1117 if (fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize)
rlm@1 1118 {
rlm@1 1119 fclose(file);
rlm@1 1120 return false;
rlm@1 1121 }
rlm@1 1122 }
rlm@1 1123 else
rlm@1 1124 {
rlm@1 1125 if (fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000)
rlm@1 1126 {
rlm@1 1127 fclose(file);
rlm@1 1128 return false;
rlm@1 1129 }
rlm@1 1130 }
rlm@1 1131 }
rlm@1 1132 else
rlm@1 1133 {
rlm@1 1134 if (fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize)
rlm@1 1135 {
rlm@1 1136 fclose(file);
rlm@1 1137 return false;
rlm@1 1138 }
rlm@1 1139 }
rlm@1 1140 fclose(file);
rlm@1 1141 }
rlm@1 1142
rlm@1 1143 return true;
rlm@1 1144 }
rlm@1 1145
rlm@1 1146 bool CPUReadGSASnapshot(const char *fileName)
rlm@1 1147 {
rlm@1 1148 int i;
rlm@1 1149 FILE *file = fopen(fileName, "rb");
rlm@1 1150
rlm@1 1151 if (!file)
rlm@1 1152 {
rlm@1 1153 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
rlm@1 1154 return false;
rlm@1 1155 }
rlm@1 1156
rlm@1 1157 // check file size to know what we should read
rlm@1 1158 fseek(file, 0, SEEK_END);
rlm@1 1159
rlm@1 1160 // long size = ftell(file);
rlm@1 1161 fseek(file, 0x0, SEEK_SET);
rlm@1 1162 fread(&i, 1, 4, file);
rlm@1 1163 fseek(file, i, SEEK_CUR); // Skip SharkPortSave
rlm@1 1164 fseek(file, 4, SEEK_CUR); // skip some sort of flag
rlm@1 1165 fread(&i, 1, 4, file); // name length
rlm@1 1166 fseek(file, i, SEEK_CUR); // skip name
rlm@1 1167 fread(&i, 1, 4, file); // desc length
rlm@1 1168 fseek(file, i, SEEK_CUR); // skip desc
rlm@1 1169 fread(&i, 1, 4, file); // notes length
rlm@1 1170 fseek(file, i, SEEK_CUR); // skip notes
rlm@1 1171 int saveSize;
rlm@1 1172 fread(&saveSize, 1, 4, file); // read length
rlm@1 1173 saveSize -= 0x1c; // remove header size
rlm@1 1174 char buffer[17];
rlm@1 1175 char buffer2[17];
rlm@1 1176 fread(buffer, 1, 16, file);
rlm@1 1177 buffer[16] = 0;
rlm@1 1178 for (i = 0; i < 16; i++)
rlm@1 1179 if (buffer[i] < 32)
rlm@1 1180 buffer[i] = 32;
rlm@1 1181 memcpy(buffer2, &rom[0xa0], 16);
rlm@1 1182 buffer2[16] = 0;
rlm@1 1183 for (i = 0; i < 16; i++)
rlm@1 1184 if (buffer2[i] < 32)
rlm@1 1185 buffer2[i] = 32;
rlm@1 1186 if (memcmp(buffer, buffer2, 16))
rlm@1 1187 {
rlm@1 1188 systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR,
rlm@1 1189 N_("Cannot import snapshot for %s. Current game is %s"),
rlm@1 1190 buffer,
rlm@1 1191 buffer2);
rlm@1 1192 fclose(file);
rlm@1 1193 return false;
rlm@1 1194 }
rlm@1 1195 fseek(file, 12, SEEK_CUR); // skip some flags
rlm@1 1196 if (saveSize >= 65536)
rlm@1 1197 {
rlm@1 1198 if (fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize)
rlm@1 1199 {
rlm@1 1200 fclose(file);
rlm@1 1201 return false;
rlm@1 1202 }
rlm@1 1203 }
rlm@1 1204 else
rlm@1 1205 {
rlm@1 1206 systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE,
rlm@1 1207 N_("Unsupported snapshot file %s"),
rlm@1 1208 fileName);
rlm@1 1209 fclose(file);
rlm@1 1210 return false;
rlm@1 1211 }
rlm@1 1212 fclose(file);
rlm@1 1213 CPUReset();
rlm@1 1214 return true;
rlm@1 1215 }
rlm@1 1216
rlm@1 1217 bool CPUWriteGSASnapshot(const char *fileName,
rlm@1 1218 const char *title,
rlm@1 1219 const char *desc,
rlm@1 1220 const char *notes)
rlm@1 1221 {
rlm@1 1222 FILE *file = fopen(fileName, "wb");
rlm@1 1223
rlm@1 1224 if (!file)
rlm@1 1225 {
rlm@1 1226 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
rlm@1 1227 return false;
rlm@1 1228 }
rlm@1 1229
rlm@1 1230 u8 buffer[17];
rlm@1 1231
rlm@1 1232 utilPutDword(buffer, 0x0d); // SharkPortSave length
rlm@1 1233 fwrite(buffer, 1, 4, file);
rlm@1 1234 fwrite("SharkPortSave", 1, 0x0d, file);
rlm@1 1235 utilPutDword(buffer, 0x000f0000);
rlm@1 1236 fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save
rlm@1 1237 utilPutDword(buffer, strlen(title));
rlm@1 1238 fwrite(buffer, 1, 4, file); // title length
rlm@1 1239 fwrite(title, 1, strlen(title), file);
rlm@1 1240 utilPutDword(buffer, strlen(desc));
rlm@1 1241 fwrite(buffer, 1, 4, file); // desc length
rlm@1 1242 fwrite(desc, 1, strlen(desc), file);
rlm@1 1243 utilPutDword(buffer, strlen(notes));
rlm@1 1244 fwrite(buffer, 1, 4, file); // notes length
rlm@1 1245 fwrite(notes, 1, strlen(notes), file);
rlm@1 1246 int saveSize = 0x10000;
rlm@1 1247 if (gbaSaveType == 2)
rlm@1 1248 saveSize = flashSize;
rlm@1 1249 int totalSize = saveSize + 0x1c;
rlm@1 1250
rlm@1 1251 utilPutDword(buffer, totalSize); // length of remainder of save - CRC
rlm@1 1252 fwrite(buffer, 1, 4, file);
rlm@1 1253
rlm@1 1254 char temp[0x2001c];
rlm@1 1255 memset(temp, 0, 28);
rlm@1 1256 memcpy(temp, &rom[0xa0], 16); // copy internal name
rlm@1 1257 temp[0x10] = rom[0xbe]; // reserved area (old checksum)
rlm@1 1258 temp[0x11] = rom[0xbf]; // reserved area (old checksum)
rlm@1 1259 temp[0x12] = rom[0xbd]; // complement check
rlm@1 1260 temp[0x13] = rom[0xb0]; // maker
rlm@1 1261 temp[0x14] = 1; // 1 save ?
rlm@1 1262 memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save
rlm@1 1263 fwrite(temp, 1, totalSize, file); // write save + header
rlm@1 1264 u32 crc = 0;
rlm@1 1265
rlm@1 1266 for (int i = 0; i < totalSize; i++)
rlm@1 1267 {
rlm@1 1268 crc += ((u32)temp[i] << (crc % 0x18));
rlm@1 1269 }
rlm@1 1270
rlm@1 1271 utilPutDword(buffer, crc);
rlm@1 1272 fwrite(buffer, 1, 4, file); // CRC?
rlm@1 1273
rlm@1 1274 fclose(file);
rlm@1 1275 return true;
rlm@1 1276 }
rlm@1 1277
rlm@1 1278 bool CPUImportEepromFile(const char *fileName)
rlm@1 1279 {
rlm@1 1280 FILE *file = fopen(fileName, "rb");
rlm@1 1281
rlm@1 1282 if (!file)
rlm@1 1283 return false;
rlm@1 1284
rlm@1 1285 // check file size to know what we should read
rlm@1 1286 fseek(file, 0, SEEK_END);
rlm@1 1287
rlm@1 1288 long size = ftell(file);
rlm@1 1289 fseek(file, 0, SEEK_SET);
rlm@1 1290 if (size == 512 || size == 0x2000)
rlm@1 1291 {
rlm@1 1292 if (fread(eepromData, 1, size, file) != (size_t)size)
rlm@1 1293 {
rlm@1 1294 fclose(file);
rlm@1 1295 return false;
rlm@1 1296 }
rlm@1 1297 for (int i = 0; i < size; )
rlm@1 1298 {
rlm@1 1299 u8 tmp = eepromData[i];
rlm@1 1300 eepromData[i] = eepromData[7 - i];
rlm@1 1301 eepromData[7 - i] = tmp;
rlm@1 1302 i++;
rlm@1 1303 tmp = eepromData[i];
rlm@1 1304 eepromData[i] = eepromData[7 - i];
rlm@1 1305 eepromData[7 - i] = tmp;
rlm@1 1306 i++;
rlm@1 1307 tmp = eepromData[i];
rlm@1 1308 eepromData[i] = eepromData[7 - i];
rlm@1 1309 eepromData[7 - i] = tmp;
rlm@1 1310 i++;
rlm@1 1311 tmp = eepromData[i];
rlm@1 1312 eepromData[i] = eepromData[7 - i];
rlm@1 1313 eepromData[7 - i] = tmp;
rlm@1 1314 i++;
rlm@1 1315 i += 4;
rlm@1 1316 }
rlm@1 1317 }
rlm@1 1318 else
rlm@1 1319 {
rlm@1 1320 fclose(file);
rlm@1 1321 return false;
rlm@1 1322 }
rlm@1 1323 fclose(file);
rlm@1 1324 return true;
rlm@1 1325 }
rlm@1 1326
rlm@1 1327 bool CPUReadBatteryFromStream(gzFile gzFile)
rlm@1 1328 {
rlm@1 1329 if (!gzFile)
rlm@1 1330 return false;
rlm@1 1331
rlm@1 1332 int version = utilReadInt(gzFile);
rlm@1 1333
rlm@1 1334 // for simplicity, we put both types of battery files should be in the stream, even if one's empty
rlm@1 1335 eepromReadGame(gzFile, version);
rlm@1 1336 flashReadGame(gzFile, version);
rlm@1 1337
rlm@1 1338 return true;
rlm@1 1339 }
rlm@1 1340
rlm@1 1341 bool CPUReadBatteryFile(const char *fileName)
rlm@1 1342 {
rlm@1 1343 FILE *file = fopen(fileName, "rb");
rlm@1 1344
rlm@1 1345 if (!file)
rlm@1 1346 return false;
rlm@1 1347
rlm@1 1348 // check file size to know what we should read
rlm@1 1349 fseek(file, 0, SEEK_END);
rlm@1 1350
rlm@1 1351 long size = ftell(file);
rlm@1 1352 fseek(file, 0, SEEK_SET);
rlm@1 1353 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
rlm@1 1354
rlm@1 1355 if (size == 512 || size == 0x2000)
rlm@1 1356 {
rlm@1 1357 if (fread(eepromData, 1, size, file) != (size_t)size)
rlm@1 1358 {
rlm@1 1359 fclose(file);
rlm@1 1360 return false;
rlm@1 1361 }
rlm@1 1362 }
rlm@1 1363 else
rlm@1 1364 {
rlm@1 1365 if (size == 0x20000)
rlm@1 1366 {
rlm@1 1367 if (fread(flashSaveMemory, 1, 0x20000, file) != 0x20000)
rlm@1 1368 {
rlm@1 1369 fclose(file);
rlm@1 1370 return false;
rlm@1 1371 }
rlm@1 1372 flashSetSize(0x20000);
rlm@1 1373 }
rlm@1 1374 else
rlm@1 1375 {
rlm@1 1376 if (fread(flashSaveMemory, 1, 0x10000, file) != 0x10000)
rlm@1 1377 {
rlm@1 1378 fclose(file);
rlm@1 1379 return false;
rlm@1 1380 }
rlm@1 1381 flashSetSize(0x10000);
rlm@1 1382 }
rlm@1 1383 }
rlm@1 1384 fclose(file);
rlm@1 1385 return true;
rlm@1 1386 }
rlm@1 1387
rlm@1 1388 bool CPUWritePNGFile(const char *fileName)
rlm@1 1389 {
rlm@1 1390 return utilWritePNGFile(fileName, 240, 160, pix);
rlm@1 1391 }
rlm@1 1392
rlm@1 1393 bool CPUWriteBMPFile(const char *fileName)
rlm@1 1394 {
rlm@1 1395 return utilWriteBMPFile(fileName, 240, 160, pix);
rlm@1 1396 }
rlm@1 1397
rlm@1 1398 void CPUCleanUp()
rlm@1 1399 {
rlm@1 1400 newFrame = true;
rlm@1 1401
rlm@1 1402 GBASystemCounters.frameCount = 0;
rlm@1 1403 GBASystemCounters.lagCount = 0;
rlm@1 1404 GBASystemCounters.extraCount = 0;
rlm@1 1405 GBASystemCounters.lagged = true;
rlm@1 1406 GBASystemCounters.laggedLast = true;
rlm@1 1407
rlm@1 1408 #ifdef PROFILING
rlm@1 1409 if (profilingTicksReload)
rlm@1 1410 {
rlm@1 1411 profCleanup();
rlm@1 1412 }
rlm@1 1413 #endif
rlm@1 1414
rlm@1 1415 #if (defined(WIN32) && !defined(SDL))
rlm@1 1416 #define FreeMappedMem(name, mapName, offset) \
rlm@1 1417 if (name != NULL) { \
rlm@1 1418 UnmapViewOfFile((name) - (offset)); \
rlm@1 1419 name = NULL; \
rlm@1 1420 CloseHandle(mapName); \
rlm@1 1421 }
rlm@1 1422 #else
rlm@1 1423 #define FreeMappedMem(name, mapName, offset) \
rlm@1 1424 if (name != NULL) { \
rlm@1 1425 free(name); \
rlm@1 1426 name = NULL; \
rlm@1 1427 }
rlm@1 1428 #endif
rlm@1 1429
rlm@1 1430 FreeMappedMem(rom, mapROM, 0);
rlm@1 1431 FreeMappedMem(vram, mapVRAM, 0);
rlm@1 1432 FreeMappedMem(paletteRAM, mapPALETTERAM, 0);
rlm@1 1433 FreeMappedMem(internalRAM, mapIRAM, 0);
rlm@1 1434 FreeMappedMem(workRAM, mapWORKRAM, 0);
rlm@1 1435 FreeMappedMem(bios, mapBIOS, 0);
rlm@1 1436 FreeMappedMem(pix, mapPIX, 4);
rlm@1 1437 FreeMappedMem(oam, mapOAM, 0);
rlm@1 1438 FreeMappedMem(ioMem, mapIOMEM, 0);
rlm@1 1439
rlm@1 1440 eepromErase();
rlm@1 1441 flashErase();
rlm@1 1442
rlm@1 1443 elfCleanUp();
rlm@1 1444
rlm@1 1445 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
rlm@1 1446
rlm@1 1447 systemClearJoypads();
rlm@1 1448 systemResetSensor();
rlm@1 1449
rlm@1 1450 // gbaLastTime = gbaFrameCount = 0;
rlm@1 1451 systemRefreshScreen();
rlm@1 1452 }
rlm@1 1453
rlm@1 1454 int CPULoadRom(const char *szFile)
rlm@1 1455 {
rlm@1 1456 int size = 0x2000000;
rlm@1 1457
rlm@1 1458 if (rom != NULL)
rlm@1 1459 {
rlm@1 1460 CPUCleanUp();
rlm@1 1461 }
rlm@1 1462
rlm@1 1463 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
rlm@1 1464
rlm@1 1465 // size+4 is so RAM search and watch are safe to read any byte in the allocated region as a 4-byte int
rlm@1 1466 #if (defined(WIN32) && !defined(SDL))
rlm@1 1467 #define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \
rlm@1 1468 mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), nameStr); \
rlm@1 1469 if ((mapName) && GetLastError() == ERROR_ALREADY_EXISTS) { \
rlm@1 1470 CloseHandle(mapName); \
rlm@1 1471 mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), NULL); \
rlm@1 1472 } \
rlm@1 1473 name = (u8 *)MapViewOfFile(mapName, FILE_MAP_WRITE, 0, 0, 0) + (offset); \
rlm@1 1474 if ((name) == NULL) { \
rlm@1 1475 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \
rlm@1 1476 CPUCleanUp(); \
rlm@1 1477 return 0; \
rlm@1 1478 } \
rlm@1 1479 memset(name, 0, size + 4);
rlm@1 1480 #else
rlm@1 1481 #define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \
rlm@1 1482 name = (u8 *)(useCalloc ? calloc(1, size + 4) : malloc(size + 4)); \
rlm@1 1483 if ((name) == NULL) { \
rlm@1 1484 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \
rlm@1 1485 CPUCleanUp(); \
rlm@1 1486 return 0; \
rlm@1 1487 } \
rlm@1 1488 memset(name, 0, size + 4);
rlm@1 1489 #endif
rlm@1 1490
rlm@1 1491 AllocMappedMem(rom, mapROM, "vbaROM", 0x2000000, false, 0);
rlm@1 1492 AllocMappedMem(workRAM, mapWORKRAM, "vbaWORKRAM", 0x40000, true, 0);
rlm@1 1493
rlm@1 1494 u8 *whereToLoad = rom;
rlm@1 1495 if (cpuIsMultiBoot)
rlm@1 1496 whereToLoad = workRAM;
rlm@1 1497
rlm@1 1498 if (utilIsELF(szFile))
rlm@1 1499 {
rlm@1 1500 FILE *f = fopen(szFile, "rb");
rlm@1 1501 if (!f)
rlm@1 1502 {
rlm@1 1503 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"),
rlm@1 1504 szFile);
rlm@1 1505 FreeMappedMem(rom, mapROM, 0);
rlm@1 1506 FreeMappedMem(workRAM, mapWORKRAM, 0);
rlm@1 1507 return 0;
rlm@1 1508 }
rlm@1 1509 bool res = elfRead(szFile, size, f);
rlm@1 1510 if (!res || size == 0)
rlm@1 1511 {
rlm@1 1512 FreeMappedMem(rom, mapROM, 0);
rlm@1 1513 FreeMappedMem(workRAM, mapWORKRAM, 0);
rlm@1 1514 elfCleanUp();
rlm@1 1515 return 0;
rlm@1 1516 }
rlm@1 1517 }
rlm@1 1518 else if (!utilLoad(szFile,
rlm@1 1519 utilIsGBAImage,
rlm@1 1520 whereToLoad,
rlm@1 1521 size))
rlm@1 1522 {
rlm@1 1523 FreeMappedMem(rom, mapROM, 0);
rlm@1 1524 FreeMappedMem(workRAM, mapWORKRAM, 0);
rlm@1 1525 return 0;
rlm@1 1526 }
rlm@1 1527
rlm@1 1528 u16 *temp = (u16 *)(rom + ((size + 1) & ~1));
rlm@1 1529 int i;
rlm@1 1530 for (i = (size + 1) & ~1; i < 0x2000000; i += 2)
rlm@1 1531 {
rlm@1 1532 WRITE16LE(temp, (i >> 1) & 0xFFFF);
rlm@1 1533 temp++;
rlm@1 1534 }
rlm@1 1535
rlm@1 1536 AllocMappedMem(bios, mapBIOS, "vbaBIOS", 0x4000, true, 0);
rlm@1 1537 AllocMappedMem(internalRAM, mapIRAM, "vbaIRAM", 0x8000, true, 0);
rlm@1 1538 AllocMappedMem(paletteRAM, mapPALETTERAM, "vbaPALETTERAM", 0x400, true, 0);
rlm@1 1539 AllocMappedMem(vram, mapVRAM, "vbaVRAM", 0x20000, true, 0);
rlm@1 1540 AllocMappedMem(oam, mapOAM, "vbaOAM", 0x400, true, 0);
rlm@1 1541
rlm@1 1542 // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel
rlm@1 1543 AllocMappedMem(pix, mapPIX, "vbaPIX", 4 * 241 * 162, true, 4);
rlm@1 1544 AllocMappedMem(ioMem, mapIOMEM, "vbaIOMEM", 0x400, true, 0);
rlm@1 1545
rlm@1 1546 CPUUpdateRenderBuffers(true);
rlm@1 1547
rlm@1 1548 return size;
rlm@1 1549 }
rlm@1 1550
rlm@1 1551 void CPUUpdateRender()
rlm@1 1552 {
rlm@1 1553 switch (DISPCNT & 7)
rlm@1 1554 {
rlm@1 1555 case 0:
rlm@1 1556 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
rlm@1 1557 cpuDisableSfx)
rlm@1 1558 renderLine = mode0RenderLine;
rlm@1 1559 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
rlm@1 1560 renderLine = mode0RenderLineNoWindow;
rlm@1 1561 else
rlm@1 1562 renderLine = mode0RenderLineAll;
rlm@1 1563 break;
rlm@1 1564 case 1:
rlm@1 1565 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
rlm@1 1566 cpuDisableSfx)
rlm@1 1567 renderLine = mode1RenderLine;
rlm@1 1568 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
rlm@1 1569 renderLine = mode1RenderLineNoWindow;
rlm@1 1570 else
rlm@1 1571 renderLine = mode1RenderLineAll;
rlm@1 1572 break;
rlm@1 1573 case 2:
rlm@1 1574 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
rlm@1 1575 cpuDisableSfx)
rlm@1 1576 renderLine = mode2RenderLine;
rlm@1 1577 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
rlm@1 1578 renderLine = mode2RenderLineNoWindow;
rlm@1 1579 else
rlm@1 1580 renderLine = mode2RenderLineAll;
rlm@1 1581 break;
rlm@1 1582 case 3:
rlm@1 1583 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
rlm@1 1584 cpuDisableSfx)
rlm@1 1585 renderLine = mode3RenderLine;
rlm@1 1586 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
rlm@1 1587 renderLine = mode3RenderLineNoWindow;
rlm@1 1588 else
rlm@1 1589 renderLine = mode3RenderLineAll;
rlm@1 1590 break;
rlm@1 1591 case 4:
rlm@1 1592 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
rlm@1 1593 cpuDisableSfx)
rlm@1 1594 renderLine = mode4RenderLine;
rlm@1 1595 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
rlm@1 1596 renderLine = mode4RenderLineNoWindow;
rlm@1 1597 else
rlm@1 1598 renderLine = mode4RenderLineAll;
rlm@1 1599 break;
rlm@1 1600 case 5:
rlm@1 1601 if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
rlm@1 1602 cpuDisableSfx)
rlm@1 1603 renderLine = mode5RenderLine;
rlm@1 1604 else if (fxOn && !windowOn && !(layerEnable & 0x8000))
rlm@1 1605 renderLine = mode5RenderLineNoWindow;
rlm@1 1606 else
rlm@1 1607 renderLine = mode5RenderLineAll;
rlm@1 1608 default:
rlm@1 1609 break;
rlm@1 1610 }
rlm@1 1611 }
rlm@1 1612
rlm@1 1613 void CPUUpdateCPSR()
rlm@1 1614 {
rlm@1 1615 u32 CPSR = reg[16].I & 0x40;
rlm@1 1616 if (N_FLAG)
rlm@1 1617 CPSR |= 0x80000000;
rlm@1 1618 if (Z_FLAG)
rlm@1 1619 CPSR |= 0x40000000;
rlm@1 1620 if (C_FLAG)
rlm@1 1621 CPSR |= 0x20000000;
rlm@1 1622 if (V_FLAG)
rlm@1 1623 CPSR |= 0x10000000;
rlm@1 1624 if (!armState)
rlm@1 1625 CPSR |= 0x00000020;
rlm@1 1626 if (!armIrqEnable)
rlm@1 1627 CPSR |= 0x80;
rlm@1 1628 CPSR |= (armMode & 0x1F);
rlm@1 1629 reg[16].I = CPSR;
rlm@1 1630 }
rlm@1 1631
rlm@1 1632 void CPUUpdateFlags(bool breakLoop)
rlm@1 1633 {
rlm@1 1634 u32 CPSR = reg[16].I;
rlm@1 1635
rlm@1 1636 N_FLAG = (CPSR & 0x80000000) ? true : false;
rlm@1 1637 Z_FLAG = (CPSR & 0x40000000) ? true : false;
rlm@1 1638 C_FLAG = (CPSR & 0x20000000) ? true : false;
rlm@1 1639 V_FLAG = (CPSR & 0x10000000) ? true : false;
rlm@1 1640 armState = (CPSR & 0x20) ? false : true;
rlm@1 1641 armIrqEnable = (CPSR & 0x80) ? false : true;
rlm@1 1642 if (breakLoop)
rlm@1 1643 {
rlm@1 1644 if (armIrqEnable && (IF & IE) && (IME & 1))
rlm@1 1645 {
rlm@1 1646 CPU_BREAK_LOOP_2;
rlm@1 1647 }
rlm@1 1648 }
rlm@1 1649 }
rlm@1 1650
rlm@1 1651 void CPUUpdateFlags()
rlm@1 1652 {
rlm@1 1653 CPUUpdateFlags(true);
rlm@1 1654 }
rlm@1 1655
rlm@1 1656 #ifdef WORDS_BIGENDIAN
rlm@1 1657 static void CPUSwap(volatile u32 *a, volatile u32 *b)
rlm@1 1658 {
rlm@1 1659 volatile u32 c = *b;
rlm@1 1660 *b = *a;
rlm@1 1661 *a = c;
rlm@1 1662 }
rlm@1 1663
rlm@1 1664 #else
rlm@1 1665 static void CPUSwap(u32 *a, u32 *b)
rlm@1 1666 {
rlm@1 1667 u32 c = *b;
rlm@1 1668 *b = *a;
rlm@1 1669 *a = c;
rlm@1 1670 }
rlm@1 1671
rlm@1 1672 #endif
rlm@1 1673
rlm@1 1674 void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
rlm@1 1675 {
rlm@1 1676 // if(armMode == mode)
rlm@1 1677 // return;
rlm@1 1678
rlm@1 1679 CPUUpdateCPSR();
rlm@1 1680
rlm@1 1681 switch (armMode)
rlm@1 1682 {
rlm@1 1683 case 0x10:
rlm@1 1684 case 0x1F:
rlm@1 1685 reg[R13_USR].I = reg[13].I;
rlm@1 1686 reg[R14_USR].I = reg[14].I;
rlm@1 1687 reg[17].I = reg[16].I;
rlm@1 1688 break;
rlm@1 1689 case 0x11:
rlm@1 1690 CPUSwap(&reg[R8_FIQ].I, &reg[8].I);
rlm@1 1691 CPUSwap(&reg[R9_FIQ].I, &reg[9].I);
rlm@1 1692 CPUSwap(&reg[R10_FIQ].I, &reg[10].I);
rlm@1 1693 CPUSwap(&reg[R11_FIQ].I, &reg[11].I);
rlm@1 1694 CPUSwap(&reg[R12_FIQ].I, &reg[12].I);
rlm@1 1695 reg[R13_FIQ].I = reg[13].I;
rlm@1 1696 reg[R14_FIQ].I = reg[14].I;
rlm@1 1697 reg[SPSR_FIQ].I = reg[17].I;
rlm@1 1698 break;
rlm@1 1699 case 0x12:
rlm@1 1700 reg[R13_IRQ].I = reg[13].I;
rlm@1 1701 reg[R14_IRQ].I = reg[14].I;
rlm@1 1702 reg[SPSR_IRQ].I = reg[17].I;
rlm@1 1703 break;
rlm@1 1704 case 0x13:
rlm@1 1705 reg[R13_SVC].I = reg[13].I;
rlm@1 1706 reg[R14_SVC].I = reg[14].I;
rlm@1 1707 reg[SPSR_SVC].I = reg[17].I;
rlm@1 1708 break;
rlm@1 1709 case 0x17:
rlm@1 1710 reg[R13_ABT].I = reg[13].I;
rlm@1 1711 reg[R14_ABT].I = reg[14].I;
rlm@1 1712 reg[SPSR_ABT].I = reg[17].I;
rlm@1 1713 break;
rlm@1 1714 case 0x1b:
rlm@1 1715 reg[R13_UND].I = reg[13].I;
rlm@1 1716 reg[R14_UND].I = reg[14].I;
rlm@1 1717 reg[SPSR_UND].I = reg[17].I;
rlm@1 1718 break;
rlm@1 1719 }
rlm@1 1720
rlm@1 1721 u32 CPSR = reg[16].I;
rlm@1 1722 u32 SPSR = reg[17].I;
rlm@1 1723
rlm@1 1724 switch (mode)
rlm@1 1725 {
rlm@1 1726 case 0x10:
rlm@1 1727 case 0x1F:
rlm@1 1728 reg[13].I = reg[R13_USR].I;
rlm@1 1729 reg[14].I = reg[R14_USR].I;
rlm@1 1730 reg[16].I = SPSR;
rlm@1 1731 break;
rlm@1 1732 case 0x11:
rlm@1 1733 CPUSwap(&reg[8].I, &reg[R8_FIQ].I);
rlm@1 1734 CPUSwap(&reg[9].I, &reg[R9_FIQ].I);
rlm@1 1735 CPUSwap(&reg[10].I, &reg[R10_FIQ].I);
rlm@1 1736 CPUSwap(&reg[11].I, &reg[R11_FIQ].I);
rlm@1 1737 CPUSwap(&reg[12].I, &reg[R12_FIQ].I);
rlm@1 1738 reg[13].I = reg[R13_FIQ].I;
rlm@1 1739 reg[14].I = reg[R14_FIQ].I;
rlm@1 1740 if (saveState)
rlm@1 1741 reg[17].I = CPSR;
rlm@1 1742 else
rlm@1 1743 reg[17].I = reg[SPSR_FIQ].I;
rlm@1 1744 break;
rlm@1 1745 case 0x12:
rlm@1 1746 reg[13].I = reg[R13_IRQ].I;
rlm@1 1747 reg[14].I = reg[R14_IRQ].I;
rlm@1 1748 reg[16].I = SPSR;
rlm@1 1749 if (saveState)
rlm@1 1750 reg[17].I = CPSR;
rlm@1 1751 else
rlm@1 1752 reg[17].I = reg[SPSR_IRQ].I;
rlm@1 1753 break;
rlm@1 1754 case 0x13:
rlm@1 1755 reg[13].I = reg[R13_SVC].I;
rlm@1 1756 reg[14].I = reg[R14_SVC].I;
rlm@1 1757 reg[16].I = SPSR;
rlm@1 1758 if (saveState)
rlm@1 1759 reg[17].I = CPSR;
rlm@1 1760 else
rlm@1 1761 reg[17].I = reg[SPSR_SVC].I;
rlm@1 1762 break;
rlm@1 1763 case 0x17:
rlm@1 1764 reg[13].I = reg[R13_ABT].I;
rlm@1 1765 reg[14].I = reg[R14_ABT].I;
rlm@1 1766 reg[16].I = SPSR;
rlm@1 1767 if (saveState)
rlm@1 1768 reg[17].I = CPSR;
rlm@1 1769 else
rlm@1 1770 reg[17].I = reg[SPSR_ABT].I;
rlm@1 1771 break;
rlm@1 1772 case 0x1b:
rlm@1 1773 reg[13].I = reg[R13_UND].I;
rlm@1 1774 reg[14].I = reg[R14_UND].I;
rlm@1 1775 reg[16].I = SPSR;
rlm@1 1776 if (saveState)
rlm@1 1777 reg[17].I = CPSR;
rlm@1 1778 else
rlm@1 1779 reg[17].I = reg[SPSR_UND].I;
rlm@1 1780 break;
rlm@1 1781 default:
rlm@1 1782 systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode);
rlm@1 1783 break;
rlm@1 1784 }
rlm@1 1785 armMode = mode;
rlm@1 1786 CPUUpdateFlags(breakLoop);
rlm@1 1787 CPUUpdateCPSR();
rlm@1 1788 }
rlm@1 1789
rlm@1 1790 void CPUSwitchMode(int mode, bool saveState)
rlm@1 1791 {
rlm@1 1792 CPUSwitchMode(mode, saveState, true);
rlm@1 1793 }
rlm@1 1794
rlm@1 1795 void CPUUndefinedException()
rlm@1 1796 {
rlm@1 1797 u32 PC = reg[15].I;
rlm@1 1798 bool savedArmState = armState;
rlm@1 1799 CPUSwitchMode(0x1b, true, false);
rlm@1 1800 reg[14].I = PC - (savedArmState ? 4 : 2);
rlm@1 1801 reg[15].I = 0x04;
rlm@1 1802 armState = true;
rlm@1 1803 armIrqEnable = false;
rlm@1 1804 armNextPC = 0x04;
rlm@1 1805 reg[15].I += 4;
rlm@1 1806 }
rlm@1 1807
rlm@1 1808 void CPUSoftwareInterrupt()
rlm@1 1809 {
rlm@1 1810 u32 PC = reg[15].I;
rlm@1 1811 bool savedArmState = armState;
rlm@1 1812 CPUSwitchMode(0x13, true, false);
rlm@1 1813 reg[14].I = PC - (savedArmState ? 4 : 2);
rlm@1 1814 reg[15].I = 0x08;
rlm@1 1815 armState = true;
rlm@1 1816 armIrqEnable = false;
rlm@1 1817 armNextPC = 0x08;
rlm@1 1818 reg[15].I += 4;
rlm@1 1819 }
rlm@1 1820
rlm@1 1821 void CPUSoftwareInterrupt(int comment)
rlm@1 1822 {
rlm@1 1823 static bool disableMessage = false;
rlm@1 1824 if (armState)
rlm@1 1825 comment >>= 16;
rlm@1 1826 #ifdef BKPT_SUPPORT
rlm@1 1827 if (comment == 0xff)
rlm@1 1828 {
rlm@1 1829 extern void (*dbgOutput)(char *, u32);
rlm@1 1830 dbgOutput(NULL, reg[0].I);
rlm@1 1831 return;
rlm@1 1832 }
rlm@1 1833 #endif
rlm@1 1834 #ifdef PROFILING
rlm@1 1835 if (comment == 0xfe)
rlm@1 1836 {
rlm@1 1837 profStartup(reg[0].I, reg[1].I);
rlm@1 1838 return;
rlm@1 1839 }
rlm@1 1840 if (comment == 0xfd)
rlm@1 1841 {
rlm@1 1842 profControl(reg[0].I);
rlm@1 1843 return;
rlm@1 1844 }
rlm@1 1845 if (comment == 0xfc)
rlm@1 1846 {
rlm@1 1847 profCleanup();
rlm@1 1848 return;
rlm@1 1849 }
rlm@1 1850 if (comment == 0xfb)
rlm@1 1851 {
rlm@1 1852 profCount();
rlm@1 1853 return;
rlm@1 1854 }
rlm@1 1855 #endif
rlm@1 1856 if (comment == 0xfa)
rlm@1 1857 {
rlm@1 1858 agbPrintFlush();
rlm@1 1859 return;
rlm@1 1860 }
rlm@1 1861 #ifdef SDL
rlm@1 1862 if (comment == 0xf9)
rlm@1 1863 {
rlm@1 1864 emulating = 0;
rlm@1 1865 CPU_BREAK_LOOP_2;
rlm@1 1866 return;
rlm@1 1867 }
rlm@1 1868 #endif
rlm@1 1869 if (useBios)
rlm@1 1870 {
rlm@1 1871 #ifdef GBA_LOGGING
rlm@1 1872 if (systemVerbose & VERBOSE_SWI)
rlm@1 1873 {
rlm@1 1874 log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
rlm@1 1875 armState ? armNextPC - 4 : armNextPC - 2,
rlm@1 1876 reg[0].I,
rlm@1 1877 reg[1].I,
rlm@1 1878 reg[2].I,
rlm@1 1879 VCOUNT);
rlm@1 1880 }
rlm@1 1881 #endif
rlm@1 1882 CPUSoftwareInterrupt();
rlm@1 1883 return;
rlm@1 1884 }
rlm@1 1885 // This would be correct, but it causes problems if uncommented
rlm@1 1886 // else {
rlm@1 1887 // biosProtected = 0xe3a02004;
rlm@1 1888 // }
rlm@1 1889
rlm@1 1890 switch (comment)
rlm@1 1891 {
rlm@1 1892 case 0x00:
rlm@1 1893 BIOS_SoftReset();
rlm@1 1894 break;
rlm@1 1895 case 0x01:
rlm@1 1896 BIOS_RegisterRamReset();
rlm@1 1897 break;
rlm@1 1898 case 0x02:
rlm@1 1899 #ifdef GBA_LOGGING
rlm@1 1900 if (systemVerbose & VERBOSE_SWI)
rlm@1 1901 {
rlm@1 1902 log("Halt: (VCOUNT = %2d)\n",
rlm@1 1903 VCOUNT);
rlm@1 1904 }
rlm@1 1905 #endif
rlm@1 1906 holdState = true;
rlm@1 1907 holdType = -1;
rlm@1 1908 break;
rlm@1 1909 case 0x03:
rlm@1 1910 #ifdef GBA_LOGGING
rlm@1 1911 if (systemVerbose & VERBOSE_SWI)
rlm@1 1912 {
rlm@1 1913 log("Stop: (VCOUNT = %2d)\n",
rlm@1 1914 VCOUNT);
rlm@1 1915 }
rlm@1 1916 #endif
rlm@1 1917 holdState = true;
rlm@1 1918 holdType = -1;
rlm@1 1919 stopState = true;
rlm@1 1920 break;
rlm@1 1921 case 0x04:
rlm@1 1922 #ifdef GBA_LOGGING
rlm@1 1923 if (systemVerbose & VERBOSE_SWI)
rlm@1 1924 {
rlm@1 1925 log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n",
rlm@1 1926 reg[0].I,
rlm@1 1927 reg[1].I,
rlm@1 1928 VCOUNT);
rlm@1 1929 }
rlm@1 1930 #endif
rlm@1 1931 CPUSoftwareInterrupt();
rlm@1 1932 break;
rlm@1 1933 case 0x05:
rlm@1 1934 #ifdef GBA_LOGGING
rlm@1 1935 if (systemVerbose & VERBOSE_SWI)
rlm@1 1936 {
rlm@1 1937 log("VBlankIntrWait: (VCOUNT = %2d)\n",
rlm@1 1938 VCOUNT);
rlm@1 1939 }
rlm@1 1940 #endif
rlm@1 1941 CPUSoftwareInterrupt();
rlm@1 1942 break;
rlm@1 1943 case 0x06:
rlm@1 1944 CPUSoftwareInterrupt();
rlm@1 1945 break;
rlm@1 1946 case 0x07:
rlm@1 1947 CPUSoftwareInterrupt();
rlm@1 1948 break;
rlm@1 1949 case 0x08:
rlm@1 1950 BIOS_Sqrt();
rlm@1 1951 break;
rlm@1 1952 case 0x09:
rlm@1 1953 BIOS_ArcTan();
rlm@1 1954 break;
rlm@1 1955 case 0x0A:
rlm@1 1956 BIOS_ArcTan2();
rlm@1 1957 break;
rlm@1 1958 case 0x0B:
rlm@1 1959 BIOS_CpuSet();
rlm@1 1960 break;
rlm@1 1961 case 0x0C:
rlm@1 1962 BIOS_CpuFastSet();
rlm@1 1963 break;
rlm@1 1964 case 0x0E:
rlm@1 1965 BIOS_BgAffineSet();
rlm@1 1966 break;
rlm@1 1967 case 0x0F:
rlm@1 1968 BIOS_ObjAffineSet();
rlm@1 1969 break;
rlm@1 1970 case 0x10:
rlm@1 1971 BIOS_BitUnPack();
rlm@1 1972 break;
rlm@1 1973 case 0x11:
rlm@1 1974 BIOS_LZ77UnCompWram();
rlm@1 1975 break;
rlm@1 1976 case 0x12:
rlm@1 1977 BIOS_LZ77UnCompVram();
rlm@1 1978 break;
rlm@1 1979 case 0x13:
rlm@1 1980 BIOS_HuffUnComp();
rlm@1 1981 break;
rlm@1 1982 case 0x14:
rlm@1 1983 BIOS_RLUnCompWram();
rlm@1 1984 break;
rlm@1 1985 case 0x15:
rlm@1 1986 BIOS_RLUnCompVram();
rlm@1 1987 break;
rlm@1 1988 case 0x16:
rlm@1 1989 BIOS_Diff8bitUnFilterWram();
rlm@1 1990 break;
rlm@1 1991 case 0x17:
rlm@1 1992 BIOS_Diff8bitUnFilterVram();
rlm@1 1993 break;
rlm@1 1994 case 0x18:
rlm@1 1995 BIOS_Diff16bitUnFilter();
rlm@1 1996 break;
rlm@1 1997 case 0x19:
rlm@1 1998 #ifdef GBA_LOGGING
rlm@1 1999 if (systemVerbose & VERBOSE_SWI)
rlm@1 2000 {
rlm@1 2001 log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n",
rlm@1 2002 reg[0].I,
rlm@1 2003 VCOUNT);
rlm@1 2004 }
rlm@1 2005 #endif
rlm@1 2006 if (reg[0].I)
rlm@1 2007 soundPause();
rlm@1 2008 else
rlm@1 2009 soundResume();
rlm@1 2010 break;
rlm@1 2011 case 0x1F:
rlm@1 2012 BIOS_MidiKey2Freq();
rlm@1 2013 break;
rlm@1 2014 case 0x2A:
rlm@1 2015 BIOS_SndDriverJmpTableCopy();
rlm@1 2016 // let it go, because we don't really emulate this function // FIXME (?)
rlm@1 2017 default:
rlm@1 2018 #ifdef GBA_LOGGING
rlm@1 2019 if (systemVerbose & VERBOSE_SWI)
rlm@1 2020 {
rlm@1 2021 log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
rlm@1 2022 armState ? armNextPC - 4 : armNextPC - 2,
rlm@1 2023 reg[0].I,
rlm@1 2024 reg[1].I,
rlm@1 2025 reg[2].I,
rlm@1 2026 VCOUNT);
rlm@1 2027 }
rlm@1 2028 #endif
rlm@1 2029
rlm@1 2030 if (!disableMessage)
rlm@1 2031 {
rlm@1 2032 systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION,
rlm@1 2033 N_(
rlm@1 2034 "Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."),
rlm@1 2035 comment,
rlm@1 2036 armMode ? armNextPC - 4 : armNextPC - 2);
rlm@1 2037 disableMessage = true;
rlm@1 2038 }
rlm@1 2039 break;
rlm@1 2040 }
rlm@1 2041 }
rlm@1 2042
rlm@1 2043 void CPUCompareVCOUNT()
rlm@1 2044 {
rlm@1 2045 if (VCOUNT == (DISPSTAT >> 8))
rlm@1 2046 {
rlm@1 2047 DISPSTAT |= 4;
rlm@1 2048 UPDATE_REG(0x04, DISPSTAT);
rlm@1 2049
rlm@1 2050 if (DISPSTAT & 0x20)
rlm@1 2051 {
rlm@1 2052 IF |= 4;
rlm@1 2053 UPDATE_REG(0x202, IF);
rlm@1 2054 }
rlm@1 2055 }
rlm@1 2056 else
rlm@1 2057 {
rlm@1 2058 DISPSTAT &= 0xFFFB;
rlm@1 2059 UPDATE_REG(0x4, DISPSTAT);
rlm@1 2060 }
rlm@1 2061 }
rlm@1 2062
rlm@1 2063 void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
rlm@1 2064 {
rlm@1 2065 int sm = s >> 24;
rlm@1 2066 int dm = d >> 24;
rlm@1 2067
rlm@1 2068 int sc = c;
rlm@1 2069
rlm@1 2070 cpuDmaCount = c;
rlm@1 2071
rlm@1 2072 if (transfer32)
rlm@1 2073 {
rlm@1 2074 s &= 0xFFFFFFFC;
rlm@1 2075 if (s < 0x02000000 && (reg[15].I >> 24))
rlm@1 2076 {
rlm@1 2077 while (c != 0)
rlm@1 2078 {
rlm@1 2079 CPUWriteMemory(d, 0);
rlm@1 2080 d += di;
rlm@1 2081 c--;
rlm@1 2082 }
rlm@1 2083 }
rlm@1 2084 else
rlm@1 2085 {
rlm@1 2086 while (c != 0)
rlm@1 2087 {
rlm@1 2088 CPUWriteMemory(d, CPUReadMemory(s));
rlm@1 2089 d += di;
rlm@1 2090 s += si;
rlm@1 2091 c--;
rlm@1 2092 }
rlm@1 2093 }
rlm@1 2094 }
rlm@1 2095 else
rlm@1 2096 {
rlm@1 2097 s &= 0xFFFFFFFE;
rlm@1 2098 si = (int)si >> 1;
rlm@1 2099 di = (int)di >> 1;
rlm@1 2100 if (s < 0x02000000 && (reg[15].I >> 24))
rlm@1 2101 {
rlm@1 2102 while (c != 0)
rlm@1 2103 {
rlm@1 2104 CPUWriteHalfWord(d, 0);
rlm@1 2105 d += di;
rlm@1 2106 c--;
rlm@1 2107 }
rlm@1 2108 }
rlm@1 2109 else
rlm@1 2110 {
rlm@1 2111 while (c != 0)
rlm@1 2112 {
rlm@1 2113 cpuDmaLast = CPUReadHalfWord(s);
rlm@1 2114 CPUWriteHalfWord(d, cpuDmaLast);
rlm@1 2115 d += di;
rlm@1 2116 s += si;
rlm@1 2117 c--;
rlm@1 2118 }
rlm@1 2119 }
rlm@1 2120 }
rlm@1 2121
rlm@1 2122 cpuDmaCount = 0;
rlm@1 2123
rlm@1 2124 int sw = 1 + memoryWaitSeq[sm & 15];
rlm@1 2125 int dw = 1 + memoryWaitSeq[dm & 15];
rlm@1 2126
rlm@1 2127 int totalTicks = 0;
rlm@1 2128
rlm@1 2129 if (transfer32)
rlm@1 2130 {
rlm@1 2131 if (!memory32[sm & 15])
rlm@1 2132 sw <<= 1;
rlm@1 2133 if (!memory32[dm & 15])
rlm@1 2134 dw <<= 1;
rlm@1 2135 }
rlm@1 2136
rlm@1 2137 totalTicks = (sw + dw) * sc;
rlm@1 2138
rlm@1 2139 cpuDmaTicksToUpdate += totalTicks;
rlm@1 2140
rlm@1 2141 if (*extCpuLoopTicks >= 0)
rlm@1 2142 {
rlm@1 2143 CPU_BREAK_LOOP;
rlm@1 2144 }
rlm@1 2145 }
rlm@1 2146
rlm@1 2147 void CPUCheckDMA(int reason, int dmamask)
rlm@1 2148 {
rlm@1 2149 cpuDmaHack = 0;
rlm@1 2150 // DMA 0
rlm@1 2151 if ((DM0CNT_H & 0x8000) && (dmamask & 1))
rlm@1 2152 {
rlm@1 2153 if (((DM0CNT_H >> 12) & 3) == reason)
rlm@1 2154 {
rlm@1 2155 u32 sourceIncrement = 4;
rlm@1 2156 u32 destIncrement = 4;
rlm@1 2157 switch ((DM0CNT_H >> 7) & 3)
rlm@1 2158 {
rlm@1 2159 case 0:
rlm@1 2160 break;
rlm@1 2161 case 1:
rlm@1 2162 sourceIncrement = (u32) - 4;
rlm@1 2163 break;
rlm@1 2164 case 2:
rlm@1 2165 sourceIncrement = 0;
rlm@1 2166 break;
rlm@1 2167 }
rlm@1 2168 switch ((DM0CNT_H >> 5) & 3)
rlm@1 2169 {
rlm@1 2170 case 0:
rlm@1 2171 break;
rlm@1 2172 case 1:
rlm@1 2173 destIncrement = (u32) - 4;
rlm@1 2174 break;
rlm@1 2175 case 2:
rlm@1 2176 destIncrement = 0;
rlm@1 2177 break;
rlm@1 2178 }
rlm@1 2179 #ifdef GBA_LOGGING
rlm@1 2180 if (systemVerbose & VERBOSE_DMA0)
rlm@1 2181 {
rlm@1 2182 int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1;
rlm@1 2183 if (DM0CNT_H & 0x0400)
rlm@1 2184 count <<= 1;
rlm@1 2185 log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest,
rlm@1 2186 DM0CNT_H,
rlm@1 2187 count);
rlm@1 2188 }
rlm@1 2189 #endif
rlm@1 2190 doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement,
rlm@1 2191 DM0CNT_L ? DM0CNT_L : 0x4000,
rlm@1 2192 DM0CNT_H & 0x0400);
rlm@1 2193 cpuDmaHack = 1;
rlm@1 2194 if (DM0CNT_H & 0x4000)
rlm@1 2195 {
rlm@1 2196 IF |= 0x0100;
rlm@1 2197 UPDATE_REG(0x202, IF);
rlm@1 2198 }
rlm@1 2199
rlm@1 2200 if (((DM0CNT_H >> 5) & 3) == 3)
rlm@1 2201 {
rlm@1 2202 dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
rlm@1 2203 }
rlm@1 2204
rlm@1 2205 if (!(DM0CNT_H & 0x0200) || (reason == 0))
rlm@1 2206 {
rlm@1 2207 DM0CNT_H &= 0x7FFF;
rlm@1 2208 UPDATE_REG(0xBA, DM0CNT_H);
rlm@1 2209 }
rlm@1 2210 }
rlm@1 2211 }
rlm@1 2212
rlm@1 2213 // DMA 1
rlm@1 2214 if ((DM1CNT_H & 0x8000) && (dmamask & 2))
rlm@1 2215 {
rlm@1 2216 if (((DM1CNT_H >> 12) & 3) == reason)
rlm@1 2217 {
rlm@1 2218 u32 sourceIncrement = 4;
rlm@1 2219 u32 destIncrement = 4;
rlm@1 2220 switch ((DM1CNT_H >> 7) & 3)
rlm@1 2221 {
rlm@1 2222 case 0:
rlm@1 2223 break;
rlm@1 2224 case 1:
rlm@1 2225 sourceIncrement = (u32) - 4;
rlm@1 2226 break;
rlm@1 2227 case 2:
rlm@1 2228 sourceIncrement = 0;
rlm@1 2229 break;
rlm@1 2230 }
rlm@1 2231 switch ((DM1CNT_H >> 5) & 3)
rlm@1 2232 {
rlm@1 2233 case 0:
rlm@1 2234 break;
rlm@1 2235 case 1:
rlm@1 2236 destIncrement = (u32) - 4;
rlm@1 2237 break;
rlm@1 2238 case 2:
rlm@1 2239 destIncrement = 0;
rlm@1 2240 break;
rlm@1 2241 }
rlm@1 2242 if (reason == 3)
rlm@1 2243 {
rlm@1 2244 #ifdef GBA_LOGGING
rlm@1 2245 if (systemVerbose & VERBOSE_DMA1)
rlm@1 2246 {
rlm@1 2247 log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
rlm@1 2248 DM1CNT_H,
rlm@1 2249 16);
rlm@1 2250 }
rlm@1 2251 #endif
rlm@1 2252 doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4,
rlm@1 2253 0x0400);
rlm@1 2254 }
rlm@1 2255 else
rlm@1 2256 {
rlm@1 2257 #ifdef GBA_LOGGING
rlm@1 2258 if (systemVerbose & VERBOSE_DMA1)
rlm@1 2259 {
rlm@1 2260 int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1;
rlm@1 2261 if (DM1CNT_H & 0x0400)
rlm@1 2262 count <<= 1;
rlm@1 2263 log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
rlm@1 2264 DM1CNT_H,
rlm@1 2265 count);
rlm@1 2266 }
rlm@1 2267 #endif
rlm@1 2268 doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement,
rlm@1 2269 DM1CNT_L ? DM1CNT_L : 0x4000,
rlm@1 2270 DM1CNT_H & 0x0400);
rlm@1 2271 }
rlm@1 2272 cpuDmaHack = 1;
rlm@1 2273
rlm@1 2274 if (DM1CNT_H & 0x4000)
rlm@1 2275 {
rlm@1 2276 IF |= 0x0200;
rlm@1 2277 UPDATE_REG(0x202, IF);
rlm@1 2278 }
rlm@1 2279
rlm@1 2280 if (((DM1CNT_H >> 5) & 3) == 3)
rlm@1 2281 {
rlm@1 2282 dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
rlm@1 2283 }
rlm@1 2284
rlm@1 2285 if (!(DM1CNT_H & 0x0200) || (reason == 0))
rlm@1 2286 {
rlm@1 2287 DM1CNT_H &= 0x7FFF;
rlm@1 2288 UPDATE_REG(0xC6, DM1CNT_H);
rlm@1 2289 }
rlm@1 2290 }
rlm@1 2291 }
rlm@1 2292
rlm@1 2293 // DMA 2
rlm@1 2294 if ((DM2CNT_H & 0x8000) && (dmamask & 4))
rlm@1 2295 {
rlm@1 2296 if (((DM2CNT_H >> 12) & 3) == reason)
rlm@1 2297 {
rlm@1 2298 u32 sourceIncrement = 4;
rlm@1 2299 u32 destIncrement = 4;
rlm@1 2300 switch ((DM2CNT_H >> 7) & 3)
rlm@1 2301 {
rlm@1 2302 case 0:
rlm@1 2303 break;
rlm@1 2304 case 1:
rlm@1 2305 sourceIncrement = (u32) - 4;
rlm@1 2306 break;
rlm@1 2307 case 2:
rlm@1 2308 sourceIncrement = 0;
rlm@1 2309 break;
rlm@1 2310 }
rlm@1 2311 switch ((DM2CNT_H >> 5) & 3)
rlm@1 2312 {
rlm@1 2313 case 0:
rlm@1 2314 break;
rlm@1 2315 case 1:
rlm@1 2316 destIncrement = (u32) - 4;
rlm@1 2317 break;
rlm@1 2318 case 2:
rlm@1 2319 destIncrement = 0;
rlm@1 2320 break;
rlm@1 2321 }
rlm@1 2322 if (reason == 3)
rlm@1 2323 {
rlm@1 2324 #ifdef GBA_LOGGING
rlm@1 2325 if (systemVerbose & VERBOSE_DMA2)
rlm@1 2326 {
rlm@1 2327 int count = (4) << 2;
rlm@1 2328 log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
rlm@1 2329 DM2CNT_H,
rlm@1 2330 count);
rlm@1 2331 }
rlm@1 2332 #endif
rlm@1 2333 doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4,
rlm@1 2334 0x0400);
rlm@1 2335 }
rlm@1 2336 else
rlm@1 2337 {
rlm@1 2338 #ifdef GBA_LOGGING
rlm@1 2339 if (systemVerbose & VERBOSE_DMA2)
rlm@1 2340 {
rlm@1 2341 int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1;
rlm@1 2342 if (DM2CNT_H & 0x0400)
rlm@1 2343 count <<= 1;
rlm@1 2344 log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
rlm@1 2345 DM2CNT_H,
rlm@1 2346 count);
rlm@1 2347 }
rlm@1 2348 #endif
rlm@1 2349 doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement,
rlm@1 2350 DM2CNT_L ? DM2CNT_L : 0x4000,
rlm@1 2351 DM2CNT_H & 0x0400);
rlm@1 2352 }
rlm@1 2353 cpuDmaHack = 1;
rlm@1 2354 if (DM2CNT_H & 0x4000)
rlm@1 2355 {
rlm@1 2356 IF |= 0x0400;
rlm@1 2357 UPDATE_REG(0x202, IF);
rlm@1 2358 }
rlm@1 2359
rlm@1 2360 if (((DM2CNT_H >> 5) & 3) == 3)
rlm@1 2361 {
rlm@1 2362 dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
rlm@1 2363 }
rlm@1 2364
rlm@1 2365 if (!(DM2CNT_H & 0x0200) || (reason == 0))
rlm@1 2366 {
rlm@1 2367 DM2CNT_H &= 0x7FFF;
rlm@1 2368 UPDATE_REG(0xD2, DM2CNT_H);
rlm@1 2369 }
rlm@1 2370 }
rlm@1 2371 }
rlm@1 2372
rlm@1 2373 // DMA 3
rlm@1 2374 if ((DM3CNT_H & 0x8000) && (dmamask & 8))
rlm@1 2375 {
rlm@1 2376 if (((DM3CNT_H >> 12) & 3) == reason)
rlm@1 2377 {
rlm@1 2378 u32 sourceIncrement = 4;
rlm@1 2379 u32 destIncrement = 4;
rlm@1 2380 switch ((DM3CNT_H >> 7) & 3)
rlm@1 2381 {
rlm@1 2382 case 0:
rlm@1 2383 break;
rlm@1 2384 case 1:
rlm@1 2385 sourceIncrement = (u32) - 4;
rlm@1 2386 break;
rlm@1 2387 case 2:
rlm@1 2388 sourceIncrement = 0;
rlm@1 2389 break;
rlm@1 2390 }
rlm@1 2391 switch ((DM3CNT_H >> 5) & 3)
rlm@1 2392 {
rlm@1 2393 case 0:
rlm@1 2394 break;
rlm@1 2395 case 1:
rlm@1 2396 destIncrement = (u32) - 4;
rlm@1 2397 break;
rlm@1 2398 case 2:
rlm@1 2399 destIncrement = 0;
rlm@1 2400 break;
rlm@1 2401 }
rlm@1 2402 #ifdef GBA_LOGGING
rlm@1 2403 if (systemVerbose & VERBOSE_DMA3)
rlm@1 2404 {
rlm@1 2405 int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1;
rlm@1 2406 if (DM3CNT_H & 0x0400)
rlm@1 2407 count <<= 1;
rlm@1 2408 log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest,
rlm@1 2409 DM3CNT_H,
rlm@1 2410 count);
rlm@1 2411 }
rlm@1 2412 #endif
rlm@1 2413 doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement,
rlm@1 2414 DM3CNT_L ? DM3CNT_L : 0x10000,
rlm@1 2415 DM3CNT_H & 0x0400);
rlm@1 2416 if (DM3CNT_H & 0x4000)
rlm@1 2417 {
rlm@1 2418 IF |= 0x0800;
rlm@1 2419 UPDATE_REG(0x202, IF);
rlm@1 2420 }
rlm@1 2421
rlm@1 2422 if (((DM3CNT_H >> 5) & 3) == 3)
rlm@1 2423 {
rlm@1 2424 dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
rlm@1 2425 }
rlm@1 2426
rlm@1 2427 if (!(DM3CNT_H & 0x0200) || (reason == 0))
rlm@1 2428 {
rlm@1 2429 DM3CNT_H &= 0x7FFF;
rlm@1 2430 UPDATE_REG(0xDE, DM3CNT_H);
rlm@1 2431 }
rlm@1 2432 }
rlm@1 2433 }
rlm@1 2434 cpuDmaHack = 0;
rlm@1 2435 }
rlm@1 2436
rlm@1 2437 void CPUUpdateRegister(u32 address, u16 value)
rlm@1 2438 {
rlm@1 2439 switch (address)
rlm@1 2440 {
rlm@1 2441 case 0x00:
rlm@1 2442 {
rlm@1 2443 bool change = ((DISPCNT ^ value) & 0x80) ? true : false;
rlm@1 2444 bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false;
rlm@1 2445 DISPCNT = (value & 0xFFF7);
rlm@1 2446 UPDATE_REG(0x00, DISPCNT);
rlm@1 2447 layerEnable = layerSettings & value;
rlm@1 2448 windowOn = (layerEnable & 0x6000) ? true : false;
rlm@1 2449 if (change && !((value & 0x80)))
rlm@1 2450 {
rlm@1 2451 if (!(DISPSTAT & 1))
rlm@1 2452 {
rlm@1 2453 lcdTicks = 960;
rlm@1 2454 // VCOUNT = 0;
rlm@1 2455 // UPDATE_REG(0x06, VCOUNT);
rlm@1 2456 DISPSTAT &= 0xFFFC;
rlm@1 2457 UPDATE_REG(0x04, DISPSTAT);
rlm@1 2458 CPUCompareVCOUNT();
rlm@1 2459 }
rlm@1 2460 // (*renderLine)();
rlm@1 2461 }
rlm@1 2462 CPUUpdateRender();
rlm@1 2463 // we only care about changes in BG0-BG3
rlm@1 2464 if (changeBG)
rlm@1 2465 CPUUpdateRenderBuffers(false);
rlm@1 2466 // CPUUpdateTicks();
rlm@1 2467 break;
rlm@1 2468 }
rlm@1 2469 case 0x04:
rlm@1 2470 DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7);
rlm@1 2471 UPDATE_REG(0x04, DISPSTAT);
rlm@1 2472 break;
rlm@1 2473 case 0x06:
rlm@1 2474 // not writable
rlm@1 2475 break;
rlm@1 2476 case 0x08:
rlm@1 2477 BG0CNT = (value & 0xDFCF);
rlm@1 2478 UPDATE_REG(0x08, BG0CNT);
rlm@1 2479 break;
rlm@1 2480 case 0x0A:
rlm@1 2481 BG1CNT = (value & 0xDFCF);
rlm@1 2482 UPDATE_REG(0x0A, BG1CNT);
rlm@1 2483 break;
rlm@1 2484 case 0x0C:
rlm@1 2485 BG2CNT = (value & 0xFFCF);
rlm@1 2486 UPDATE_REG(0x0C, BG2CNT);
rlm@1 2487 break;
rlm@1 2488 case 0x0E:
rlm@1 2489 BG3CNT = (value & 0xFFCF);
rlm@1 2490 UPDATE_REG(0x0E, BG3CNT);
rlm@1 2491 break;
rlm@1 2492 case 0x10:
rlm@1 2493 BG0HOFS = value & 511;
rlm@1 2494 UPDATE_REG(0x10, BG0HOFS);
rlm@1 2495 break;
rlm@1 2496 case 0x12:
rlm@1 2497 BG0VOFS = value & 511;
rlm@1 2498 UPDATE_REG(0x12, BG0VOFS);
rlm@1 2499 break;
rlm@1 2500 case 0x14:
rlm@1 2501 BG1HOFS = value & 511;
rlm@1 2502 UPDATE_REG(0x14, BG1HOFS);
rlm@1 2503 break;
rlm@1 2504 case 0x16:
rlm@1 2505 BG1VOFS = value & 511;
rlm@1 2506 UPDATE_REG(0x16, BG1VOFS);
rlm@1 2507 break;
rlm@1 2508 case 0x18:
rlm@1 2509 BG2HOFS = value & 511;
rlm@1 2510 UPDATE_REG(0x18, BG2HOFS);
rlm@1 2511 break;
rlm@1 2512 case 0x1A:
rlm@1 2513 BG2VOFS = value & 511;
rlm@1 2514 UPDATE_REG(0x1A, BG2VOFS);
rlm@1 2515 break;
rlm@1 2516 case 0x1C:
rlm@1 2517 BG3HOFS = value & 511;
rlm@1 2518 UPDATE_REG(0x1C, BG3HOFS);
rlm@1 2519 break;
rlm@1 2520 case 0x1E:
rlm@1 2521 BG3VOFS = value & 511;
rlm@1 2522 UPDATE_REG(0x1E, BG3VOFS);
rlm@1 2523 break;
rlm@1 2524 case 0x20:
rlm@1 2525 BG2PA = value;
rlm@1 2526 UPDATE_REG(0x20, BG2PA);
rlm@1 2527 break;
rlm@1 2528 case 0x22:
rlm@1 2529 BG2PB = value;
rlm@1 2530 UPDATE_REG(0x22, BG2PB);
rlm@1 2531 break;
rlm@1 2532 case 0x24:
rlm@1 2533 BG2PC = value;
rlm@1 2534 UPDATE_REG(0x24, BG2PC);
rlm@1 2535 break;
rlm@1 2536 case 0x26:
rlm@1 2537 BG2PD = value;
rlm@1 2538 UPDATE_REG(0x26, BG2PD);
rlm@1 2539 break;
rlm@1 2540 case 0x28:
rlm@1 2541 BG2X_L = value;
rlm@1 2542 UPDATE_REG(0x28, BG2X_L);
rlm@1 2543 gfxBG2Changed |= 1;
rlm@1 2544 break;
rlm@1 2545 case 0x2A:
rlm@1 2546 BG2X_H = (value & 0xFFF);
rlm@1 2547 UPDATE_REG(0x2A, BG2X_H);
rlm@1 2548 gfxBG2Changed |= 1;
rlm@1 2549 break;
rlm@1 2550 case 0x2C:
rlm@1 2551 BG2Y_L = value;
rlm@1 2552 UPDATE_REG(0x2C, BG2Y_L);
rlm@1 2553 gfxBG2Changed |= 2;
rlm@1 2554 break;
rlm@1 2555 case 0x2E:
rlm@1 2556 BG2Y_H = value & 0xFFF;
rlm@1 2557 UPDATE_REG(0x2E, BG2Y_H);
rlm@1 2558 gfxBG2Changed |= 2;
rlm@1 2559 break;
rlm@1 2560 case 0x30:
rlm@1 2561 BG3PA = value;
rlm@1 2562 UPDATE_REG(0x30, BG3PA);
rlm@1 2563 break;
rlm@1 2564 case 0x32:
rlm@1 2565 BG3PB = value;
rlm@1 2566 UPDATE_REG(0x32, BG3PB);
rlm@1 2567 break;
rlm@1 2568 case 0x34:
rlm@1 2569 BG3PC = value;
rlm@1 2570 UPDATE_REG(0x34, BG3PC);
rlm@1 2571 break;
rlm@1 2572 case 0x36:
rlm@1 2573 BG3PD = value;
rlm@1 2574 UPDATE_REG(0x36, BG3PD);
rlm@1 2575 break;
rlm@1 2576 case 0x38:
rlm@1 2577 BG3X_L = value;
rlm@1 2578 UPDATE_REG(0x38, BG3X_L);
rlm@1 2579 gfxBG3Changed |= 1;
rlm@1 2580 break;
rlm@1 2581 case 0x3A:
rlm@1 2582 BG3X_H = value & 0xFFF;
rlm@1 2583 UPDATE_REG(0x3A, BG3X_H);
rlm@1 2584 gfxBG3Changed |= 1;
rlm@1 2585 break;
rlm@1 2586 case 0x3C:
rlm@1 2587 BG3Y_L = value;
rlm@1 2588 UPDATE_REG(0x3C, BG3Y_L);
rlm@1 2589 gfxBG3Changed |= 2;
rlm@1 2590 break;
rlm@1 2591 case 0x3E:
rlm@1 2592 BG3Y_H = value & 0xFFF;
rlm@1 2593 UPDATE_REG(0x3E, BG3Y_H);
rlm@1 2594 gfxBG3Changed |= 2;
rlm@1 2595 break;
rlm@1 2596 case 0x40:
rlm@1 2597 WIN0H = value;
rlm@1 2598 UPDATE_REG(0x40, WIN0H);
rlm@1 2599 CPUUpdateWindow0();
rlm@1 2600 break;
rlm@1 2601 case 0x42:
rlm@1 2602 WIN1H = value;
rlm@1 2603 UPDATE_REG(0x42, WIN1H);
rlm@1 2604 CPUUpdateWindow1();
rlm@1 2605 break;
rlm@1 2606 case 0x44:
rlm@1 2607 WIN0V = value;
rlm@1 2608 UPDATE_REG(0x44, WIN0V);
rlm@1 2609 break;
rlm@1 2610 case 0x46:
rlm@1 2611 WIN1V = value;
rlm@1 2612 UPDATE_REG(0x46, WIN1V);
rlm@1 2613 break;
rlm@1 2614 case 0x48:
rlm@1 2615 WININ = value & 0x3F3F;
rlm@1 2616 UPDATE_REG(0x48, WININ);
rlm@1 2617 break;
rlm@1 2618 case 0x4A:
rlm@1 2619 WINOUT = value & 0x3F3F;
rlm@1 2620 UPDATE_REG(0x4A, WINOUT);
rlm@1 2621 break;
rlm@1 2622 case 0x4C:
rlm@1 2623 MOSAIC = value;
rlm@1 2624 UPDATE_REG(0x4C, MOSAIC);
rlm@1 2625 break;
rlm@1 2626 case 0x50:
rlm@1 2627 BLDMOD = value & 0x3FFF;
rlm@1 2628 UPDATE_REG(0x50, BLDMOD);
rlm@1 2629 fxOn = ((BLDMOD >> 6) & 3) != 0;
rlm@1 2630 CPUUpdateRender();
rlm@1 2631 break;
rlm@1 2632 case 0x52:
rlm@1 2633 COLEV = value & 0x1F1F;
rlm@1 2634 UPDATE_REG(0x52, COLEV);
rlm@1 2635 break;
rlm@1 2636 case 0x54:
rlm@1 2637 COLY = value & 0x1F;
rlm@1 2638 UPDATE_REG(0x54, COLY);
rlm@1 2639 break;
rlm@1 2640 case 0x60:
rlm@1 2641 case 0x62:
rlm@1 2642 case 0x64:
rlm@1 2643 case 0x68:
rlm@1 2644 case 0x6c:
rlm@1 2645 case 0x70:
rlm@1 2646 case 0x72:
rlm@1 2647 case 0x74:
rlm@1 2648 case 0x78:
rlm@1 2649 case 0x7c:
rlm@1 2650 case 0x80:
rlm@1 2651 case 0x84:
rlm@1 2652 soundEvent(address & 0xFF, (u8)(value & 0xFF));
rlm@1 2653 soundEvent((address & 0xFF) + 1, (u8)(value >> 8));
rlm@1 2654 break;
rlm@1 2655 case 0x82:
rlm@1 2656 case 0x88:
rlm@1 2657 case 0xa0:
rlm@1 2658 case 0xa2:
rlm@1 2659 case 0xa4:
rlm@1 2660 case 0xa6:
rlm@1 2661 case 0x90:
rlm@1 2662 case 0x92:
rlm@1 2663 case 0x94:
rlm@1 2664 case 0x96:
rlm@1 2665 case 0x98:
rlm@1 2666 case 0x9a:
rlm@1 2667 case 0x9c:
rlm@1 2668 case 0x9e:
rlm@1 2669 soundEvent(address & 0xFF, value);
rlm@1 2670 break;
rlm@1 2671 case 0xB0:
rlm@1 2672 DM0SAD_L = value;
rlm@1 2673 UPDATE_REG(0xB0, DM0SAD_L);
rlm@1 2674 break;
rlm@1 2675 case 0xB2:
rlm@1 2676 DM0SAD_H = value & 0x07FF;
rlm@1 2677 UPDATE_REG(0xB2, DM0SAD_H);
rlm@1 2678 break;
rlm@1 2679 case 0xB4:
rlm@1 2680 DM0DAD_L = value;
rlm@1 2681 UPDATE_REG(0xB4, DM0DAD_L);
rlm@1 2682 break;
rlm@1 2683 case 0xB6:
rlm@1 2684 DM0DAD_H = value & 0x07FF;
rlm@1 2685 UPDATE_REG(0xB6, DM0DAD_H);
rlm@1 2686 break;
rlm@1 2687 case 0xB8:
rlm@1 2688 DM0CNT_L = value & 0x3FFF;
rlm@1 2689 UPDATE_REG(0xB8, 0);
rlm@1 2690 break;
rlm@1 2691 case 0xBA:
rlm@1 2692 {
rlm@1 2693 bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false;
rlm@1 2694 value &= 0xF7E0;
rlm@1 2695
rlm@1 2696 DM0CNT_H = value;
rlm@1 2697 UPDATE_REG(0xBA, DM0CNT_H);
rlm@1 2698
rlm@1 2699 if (start && (value & 0x8000))
rlm@1 2700 {
rlm@1 2701 dma0Source = DM0SAD_L | (DM0SAD_H << 16);
rlm@1 2702 dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
rlm@1 2703 CPUCheckDMA(0, 1);
rlm@1 2704 }
rlm@1 2705 break;
rlm@1 2706 }
rlm@1 2707 case 0xBC:
rlm@1 2708 DM1SAD_L = value;
rlm@1 2709 UPDATE_REG(0xBC, DM1SAD_L);
rlm@1 2710 break;
rlm@1 2711 case 0xBE:
rlm@1 2712 DM1SAD_H = value & 0x0FFF;
rlm@1 2713 UPDATE_REG(0xBE, DM1SAD_H);
rlm@1 2714 break;
rlm@1 2715 case 0xC0:
rlm@1 2716 DM1DAD_L = value;
rlm@1 2717 UPDATE_REG(0xC0, DM1DAD_L);
rlm@1 2718 break;
rlm@1 2719 case 0xC2:
rlm@1 2720 DM1DAD_H = value & 0x07FF;
rlm@1 2721 UPDATE_REG(0xC2, DM1DAD_H);
rlm@1 2722 break;
rlm@1 2723 case 0xC4:
rlm@1 2724 DM1CNT_L = value & 0x3FFF;
rlm@1 2725 UPDATE_REG(0xC4, 0);
rlm@1 2726 break;
rlm@1 2727 case 0xC6:
rlm@1 2728 {
rlm@1 2729 bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false;
rlm@1 2730 value &= 0xF7E0;
rlm@1 2731
rlm@1 2732 DM1CNT_H = value;
rlm@1 2733 UPDATE_REG(0xC6, DM1CNT_H);
rlm@1 2734
rlm@1 2735 if (start && (value & 0x8000))
rlm@1 2736 {
rlm@1 2737 dma1Source = DM1SAD_L | (DM1SAD_H << 16);
rlm@1 2738 dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
rlm@1 2739 CPUCheckDMA(0, 2);
rlm@1 2740 }
rlm@1 2741 break;
rlm@1 2742 }
rlm@1 2743 case 0xC8:
rlm@1 2744 DM2SAD_L = value;
rlm@1 2745 UPDATE_REG(0xC8, DM2SAD_L);
rlm@1 2746 break;
rlm@1 2747 case 0xCA:
rlm@1 2748 DM2SAD_H = value & 0x0FFF;
rlm@1 2749 UPDATE_REG(0xCA, DM2SAD_H);
rlm@1 2750 break;
rlm@1 2751 case 0xCC:
rlm@1 2752 DM2DAD_L = value;
rlm@1 2753 UPDATE_REG(0xCC, DM2DAD_L);
rlm@1 2754 break;
rlm@1 2755 case 0xCE:
rlm@1 2756 DM2DAD_H = value & 0x07FF;
rlm@1 2757 UPDATE_REG(0xCE, DM2DAD_H);
rlm@1 2758 break;
rlm@1 2759 case 0xD0:
rlm@1 2760 DM2CNT_L = value & 0x3FFF;
rlm@1 2761 UPDATE_REG(0xD0, 0);
rlm@1 2762 break;
rlm@1 2763 case 0xD2:
rlm@1 2764 {
rlm@1 2765 bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false;
rlm@1 2766
rlm@1 2767 value &= 0xF7E0;
rlm@1 2768
rlm@1 2769 DM2CNT_H = value;
rlm@1 2770 UPDATE_REG(0xD2, DM2CNT_H);
rlm@1 2771
rlm@1 2772 if (start && (value & 0x8000))
rlm@1 2773 {
rlm@1 2774 dma2Source = DM2SAD_L | (DM2SAD_H << 16);
rlm@1 2775 dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
rlm@1 2776
rlm@1 2777 CPUCheckDMA(0, 4);
rlm@1 2778 }
rlm@1 2779 break;
rlm@1 2780 }
rlm@1 2781 case 0xD4:
rlm@1 2782 DM3SAD_L = value;
rlm@1 2783 UPDATE_REG(0xD4, DM3SAD_L);
rlm@1 2784 break;
rlm@1 2785 case 0xD6:
rlm@1 2786 DM3SAD_H = value & 0x0FFF;
rlm@1 2787 UPDATE_REG(0xD6, DM3SAD_H);
rlm@1 2788 break;
rlm@1 2789 case 0xD8:
rlm@1 2790 DM3DAD_L = value;
rlm@1 2791 UPDATE_REG(0xD8, DM3DAD_L);
rlm@1 2792 break;
rlm@1 2793 case 0xDA:
rlm@1 2794 DM3DAD_H = value & 0x0FFF;
rlm@1 2795 UPDATE_REG(0xDA, DM3DAD_H);
rlm@1 2796 break;
rlm@1 2797 case 0xDC:
rlm@1 2798 DM3CNT_L = value;
rlm@1 2799 UPDATE_REG(0xDC, 0);
rlm@1 2800 break;
rlm@1 2801 case 0xDE:
rlm@1 2802 {
rlm@1 2803 bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false;
rlm@1 2804
rlm@1 2805 value &= 0xFFE0;
rlm@1 2806
rlm@1 2807 DM3CNT_H = value;
rlm@1 2808 UPDATE_REG(0xDE, DM3CNT_H);
rlm@1 2809
rlm@1 2810 if (start && (value & 0x8000))
rlm@1 2811 {
rlm@1 2812 dma3Source = DM3SAD_L | (DM3SAD_H << 16);
rlm@1 2813 dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
rlm@1 2814 CPUCheckDMA(0, 8);
rlm@1 2815 }
rlm@1 2816 break;
rlm@1 2817 }
rlm@1 2818 case 0x100:
rlm@1 2819 timer0Reload = value;
rlm@1 2820 break;
rlm@1 2821 case 0x102:
rlm@1 2822 timer0Ticks = timer0ClockReload = TIMER_TICKS[value & 3];
rlm@1 2823 if (!timer0On && (value & 0x80))
rlm@1 2824 {
rlm@1 2825 // reload the counter
rlm@1 2826 TM0D = timer0Reload;
rlm@1 2827 if (timer0ClockReload == 1)
rlm@1 2828 timer0Ticks = 0x10000 - TM0D;
rlm@1 2829 UPDATE_REG(0x100, TM0D);
rlm@1 2830 }
rlm@1 2831 timer0On = value & 0x80 ? true : false;
rlm@1 2832 TM0CNT = value & 0xC7;
rlm@1 2833 UPDATE_REG(0x102, TM0CNT);
rlm@1 2834 // CPUUpdateTicks();
rlm@1 2835 break;
rlm@1 2836 case 0x104:
rlm@1 2837 timer1Reload = value;
rlm@1 2838 break;
rlm@1 2839 case 0x106:
rlm@1 2840 timer1Ticks = timer1ClockReload = TIMER_TICKS[value & 3];
rlm@1 2841 if (!timer1On && (value & 0x80))
rlm@1 2842 {
rlm@1 2843 // reload the counter
rlm@1 2844 TM1D = timer1Reload;
rlm@1 2845 if (timer1ClockReload == 1)
rlm@1 2846 timer1Ticks = 0x10000 - TM1D;
rlm@1 2847 UPDATE_REG(0x104, TM1D);
rlm@1 2848 }
rlm@1 2849 timer1On = value & 0x80 ? true : false;
rlm@1 2850 TM1CNT = value & 0xC7;
rlm@1 2851 UPDATE_REG(0x106, TM1CNT);
rlm@1 2852 break;
rlm@1 2853 case 0x108:
rlm@1 2854 timer2Reload = value;
rlm@1 2855 break;
rlm@1 2856 case 0x10A:
rlm@1 2857 timer2Ticks = timer2ClockReload = TIMER_TICKS[value & 3];
rlm@1 2858 if (!timer2On && (value & 0x80))
rlm@1 2859 {
rlm@1 2860 // reload the counter
rlm@1 2861 TM2D = timer2Reload;
rlm@1 2862 if (timer2ClockReload == 1)
rlm@1 2863 timer2Ticks = 0x10000 - TM2D;
rlm@1 2864 UPDATE_REG(0x108, TM2D);
rlm@1 2865 }
rlm@1 2866 timer2On = value & 0x80 ? true : false;
rlm@1 2867 TM2CNT = value & 0xC7;
rlm@1 2868 UPDATE_REG(0x10A, TM2CNT);
rlm@1 2869 break;
rlm@1 2870 case 0x10C:
rlm@1 2871 timer3Reload = value;
rlm@1 2872 break;
rlm@1 2873 case 0x10E:
rlm@1 2874 timer3Ticks = timer3ClockReload = TIMER_TICKS[value & 3];
rlm@1 2875 if (!timer3On && (value & 0x80))
rlm@1 2876 {
rlm@1 2877 // reload the counter
rlm@1 2878 TM3D = timer3Reload;
rlm@1 2879 if (timer3ClockReload == 1)
rlm@1 2880 timer3Ticks = 0x10000 - TM3D;
rlm@1 2881 UPDATE_REG(0x10C, TM3D);
rlm@1 2882 }
rlm@1 2883 timer3On = value & 0x80 ? true : false;
rlm@1 2884 TM3CNT = value & 0xC7;
rlm@1 2885 UPDATE_REG(0x10E, TM3CNT);
rlm@1 2886 break;
rlm@1 2887 case 0x128:
rlm@1 2888 if (value & 0x80)
rlm@1 2889 {
rlm@1 2890 value &= 0xff7f;
rlm@1 2891 if (value & 1 && (value & 0x4000))
rlm@1 2892 {
rlm@1 2893 UPDATE_REG(0x12a, 0xFF);
rlm@1 2894 IF |= 0x80;
rlm@1 2895 UPDATE_REG(0x202, IF);
rlm@1 2896 value &= 0x7f7f;
rlm@1 2897 }
rlm@1 2898 }
rlm@1 2899 UPDATE_REG(0x128, value);
rlm@1 2900 break;
rlm@1 2901 case 0x130:
rlm@1 2902 P1 |= (value & 0x3FF);
rlm@1 2903 UPDATE_REG(0x130, P1);
rlm@1 2904 break;
rlm@1 2905 case 0x132:
rlm@1 2906 UPDATE_REG(0x132, value & 0xC3FF);
rlm@1 2907 break;
rlm@1 2908 case 0x200:
rlm@1 2909 IE = value & 0x3FFF;
rlm@1 2910 UPDATE_REG(0x200, IE);
rlm@1 2911 if ((IME & 1) && (IF & IE) && armIrqEnable)
rlm@1 2912 {
rlm@1 2913 CPU_BREAK_LOOP_2;
rlm@1 2914 }
rlm@1 2915 break;
rlm@1 2916 case 0x202:
rlm@1 2917 IF ^= (value & IF);
rlm@1 2918 UPDATE_REG(0x202, IF);
rlm@1 2919 break;
rlm@1 2920 case 0x204:
rlm@1 2921 {
rlm@1 2922 int i;
rlm@1 2923 memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3];
rlm@1 2924
rlm@1 2925 if (!speedHack)
rlm@1 2926 {
rlm@1 2927 memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 7];
rlm@1 2928 memoryWaitSeq[0x08] = memoryWaitSeq[0x09] =
rlm@1 2929 gamepakWaitState0[(value >> 2) & 7];
rlm@1 2930
rlm@1 2931 memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 7];
rlm@1 2932 memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] =
rlm@1 2933 gamepakWaitState1[(value >> 5) & 7];
rlm@1 2934
rlm@1 2935 memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 7];
rlm@1 2936 memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] =
rlm@1 2937 gamepakWaitState2[(value >> 8) & 7];
rlm@1 2938 }
rlm@1 2939 else
rlm@1 2940 {
rlm@1 2941 memoryWait[0x08] = memoryWait[0x09] = 4;
rlm@1 2942 memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 2;
rlm@1 2943
rlm@1 2944 memoryWait[0x0a] = memoryWait[0x0b] = 4;
rlm@1 2945 memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 4;
rlm@1 2946
rlm@1 2947 memoryWait[0x0c] = memoryWait[0x0d] = 4;
rlm@1 2948 memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 8;
rlm@1 2949 }
rlm@1 2950 for (i = 0; i < 16; i++)
rlm@1 2951 {
rlm@1 2952 memoryWaitFetch32[i] = memoryWait32[i] = memoryWait[i] *
rlm@1 2953 (memory32[i] ? 1 : 2);
rlm@1 2954 memoryWaitFetch[i] = memoryWait[i];
rlm@1 2955 }
rlm@1 2956 memoryWaitFetch32[3] += 1;
rlm@1 2957 memoryWaitFetch32[2] += 3;
rlm@1 2958
rlm@1 2959 prefetchActive = false;
rlm@1 2960 prefetchApplies = false;
rlm@1 2961 if (value & 0x4000)
rlm@1 2962 {
rlm@1 2963 for (i = 8; i < 16; i++)
rlm@1 2964 {
rlm@1 2965 memoryWaitFetch32[i] = 2 * cpuMemoryWait[i];
rlm@1 2966 memoryWaitFetch[i] = cpuMemoryWait[i];
rlm@1 2967 }
rlm@1 2968 if (((value & 3) == 3))
rlm@1 2969 {
rlm@1 2970 if (!memLagTempEnabled)
rlm@1 2971 {
rlm@1 2972 memoryWaitFetch[8]--; // hack to prevent inaccurately extreme lag at some points of many games (possibly
rlm@1 2973 // from no pre-fetch emulation)
rlm@1 2974 /// FIXME: how correct is this? Should it set the fetch to 0 or change fetch32 or
rlm@1 2975 // anything else?
rlm@1 2976
rlm@1 2977 prefetchActive = true;
rlm@1 2978 }
rlm@1 2979 prefetchApplies = true;
rlm@1 2980 }
rlm@1 2981 }
rlm@1 2982 //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
rlm@1 2983 //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
rlm@1 2984 prefetchPrevActive = prefetchActive;
rlm@1 2985
rlm@1 2986 UPDATE_REG(0x204, value);
rlm@1 2987 break;
rlm@1 2988 }
rlm@1 2989 case 0x208:
rlm@1 2990 IME = value & 1;
rlm@1 2991 UPDATE_REG(0x208, IME);
rlm@1 2992 if ((IME & 1) && (IF & IE) && armIrqEnable)
rlm@1 2993 {
rlm@1 2994 CPU_BREAK_LOOP_2;
rlm@1 2995 }
rlm@1 2996 break;
rlm@1 2997 case 0x300:
rlm@1 2998 if (value != 0)
rlm@1 2999 value &= 0xFFFE;
rlm@1 3000 UPDATE_REG(0x300, value);
rlm@1 3001 break;
rlm@1 3002 default:
rlm@1 3003 UPDATE_REG(address & 0x3FE, value);
rlm@1 3004 break;
rlm@1 3005 }
rlm@1 3006 }
rlm@1 3007
rlm@1 3008 void CPUWriteHalfWordWrapped(u32 address, u16 value)
rlm@1 3009 {
rlm@1 3010 #ifdef GBA_LOGGING
rlm@1 3011 if (address & 1)
rlm@1 3012 {
rlm@1 3013 if (systemVerbose & VERBOSE_UNALIGNED_MEMORY)
rlm@1 3014 {
rlm@1 3015 log("Unaligned halfword write: %04x to %08x from %08x\n",
rlm@1 3016 value,
rlm@1 3017 address,
rlm@1 3018 armMode ? armNextPC - 4 : armNextPC - 2);
rlm@1 3019 }
rlm@1 3020 }
rlm@1 3021 #endif
rlm@1 3022
rlm@1 3023 switch (address >> 24)
rlm@1 3024 {
rlm@1 3025 case 2:
rlm@1 3026 #ifdef SDL
rlm@1 3027 if (*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
rlm@1 3028 cheatsWriteHalfWord((u16 *)&workRAM[address & 0x3FFFE],
rlm@1 3029 value,
rlm@1 3030 *((u16 *)&freezeWorkRAM[address & 0x3FFFE]));
rlm@1 3031 else
rlm@1 3032 #endif
rlm@1 3033 WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]), value);
rlm@1 3034 break;
rlm@1 3035 case 3:
rlm@1 3036 #ifdef SDL
rlm@1 3037 if (*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
rlm@1 3038 cheatsWriteHalfWord((u16 *)&internalRAM[address & 0x7ffe],
rlm@1 3039 value,
rlm@1 3040 *((u16 *)&freezeInternalRAM[address & 0x7ffe]));
rlm@1 3041 else
rlm@1 3042 #endif
rlm@1 3043 WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
rlm@1 3044 break;
rlm@1 3045 case 4:
rlm@1 3046 CPUUpdateRegister(address & 0x3fe, value);
rlm@1 3047 break;
rlm@1 3048 case 5:
rlm@1 3049 WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
rlm@1 3050 break;
rlm@1 3051 case 6:
rlm@1 3052 if (address & 0x10000)
rlm@1 3053 WRITE16LE(((u16 *)&vram[address & 0x17ffe]), value);
rlm@1 3054 else
rlm@1 3055 WRITE16LE(((u16 *)&vram[address & 0x1fffe]), value);
rlm@1 3056 break;
rlm@1 3057 case 7:
rlm@1 3058 WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
rlm@1 3059 break;
rlm@1 3060 case 8:
rlm@1 3061 case 9:
rlm@1 3062 if (address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
rlm@1 3063 {
rlm@1 3064 if (!rtcWrite(address, value))
rlm@1 3065 goto unwritable;
rlm@1 3066 }
rlm@1 3067 else if (!agbPrintWrite(address, value))
rlm@1 3068 goto unwritable;
rlm@1 3069 break;
rlm@1 3070 case 13:
rlm@1 3071 if (cpuEEPROMEnabled)
rlm@1 3072 {
rlm@1 3073 eepromWrite(address, (u8)(value & 0xFF));
rlm@1 3074 break;
rlm@1 3075 }
rlm@1 3076 goto unwritable;
rlm@1 3077 case 14:
rlm@1 3078 if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)
rlm@1 3079 {
rlm@1 3080 (*cpuSaveGameFunc)(address, (u8)(value & 0xFF));
rlm@1 3081 break;
rlm@1 3082 }
rlm@1 3083 goto unwritable;
rlm@1 3084 default:
rlm@1 3085 unwritable:
rlm@1 3086 #ifdef GBA_LOGGING
rlm@1 3087 if (systemVerbose & VERBOSE_ILLEGAL_WRITE)
rlm@1 3088 {
rlm@1 3089 log("Illegal halfword write: %04x to %08x from %08x\n",
rlm@1 3090 value,
rlm@1 3091 address,
rlm@1 3092 armMode ? armNextPC - 4 : armNextPC - 2);
rlm@1 3093 }
rlm@1 3094 #endif
rlm@1 3095 break;
rlm@1 3096 }
rlm@1 3097 }
rlm@1 3098
rlm@1 3099 void CPUWriteHalfWord(u32 address, u16 value)
rlm@1 3100 {
rlm@1 3101 CPUWriteHalfWordWrapped(address, value);
rlm@1 3102 CallRegisteredLuaMemHook(address, 2, value, LUAMEMHOOK_WRITE);
rlm@1 3103 }
rlm@1 3104
rlm@1 3105 void CPUWriteByteWrapped(u32 address, u8 b)
rlm@1 3106 {
rlm@1 3107 switch (address >> 24)
rlm@1 3108 {
rlm@1 3109 case 2:
rlm@1 3110 #ifdef SDL
rlm@1 3111 if (freezeWorkRAM[address & 0x3FFFF])
rlm@1 3112 cheatsWriteByte(&workRAM[address & 0x3FFFF], b);
rlm@1 3113 else
rlm@1 3114 #endif
rlm@1 3115 workRAM[address & 0x3FFFF] = b;
rlm@1 3116 break;
rlm@1 3117 case 3:
rlm@1 3118 #ifdef SDL
rlm@1 3119 if (freezeInternalRAM[address & 0x7fff])
rlm@1 3120 cheatsWriteByte(&internalRAM[address & 0x7fff], b);
rlm@1 3121 else
rlm@1 3122 #endif
rlm@1 3123 internalRAM[address & 0x7fff] = b;
rlm@1 3124 break;
rlm@1 3125 case 4:
rlm@1 3126 switch (address & 0x3FF)
rlm@1 3127 {
rlm@1 3128 case 0x301:
rlm@1 3129 if (b == 0x80)
rlm@1 3130 stopState = true;
rlm@1 3131 holdState = 1;
rlm@1 3132 holdType = -1;
rlm@1 3133 break;
rlm@1 3134 case 0x60:
rlm@1 3135 case 0x61:
rlm@1 3136 case 0x62:
rlm@1 3137 case 0x63:
rlm@1 3138 case 0x64:
rlm@1 3139 case 0x65:
rlm@1 3140 case 0x68:
rlm@1 3141 case 0x69:
rlm@1 3142 case 0x6c:
rlm@1 3143 case 0x6d:
rlm@1 3144 case 0x70:
rlm@1 3145 case 0x71:
rlm@1 3146 case 0x72:
rlm@1 3147 case 0x73:
rlm@1 3148 case 0x74:
rlm@1 3149 case 0x75:
rlm@1 3150 case 0x78:
rlm@1 3151 case 0x79:
rlm@1 3152 case 0x7c:
rlm@1 3153 case 0x7d:
rlm@1 3154 case 0x80:
rlm@1 3155 case 0x81:
rlm@1 3156 case 0x84:
rlm@1 3157 case 0x85:
rlm@1 3158 case 0x90:
rlm@1 3159 case 0x91:
rlm@1 3160 case 0x92:
rlm@1 3161 case 0x93:
rlm@1 3162 case 0x94:
rlm@1 3163 case 0x95:
rlm@1 3164 case 0x96:
rlm@1 3165 case 0x97:
rlm@1 3166 case 0x98:
rlm@1 3167 case 0x99:
rlm@1 3168 case 0x9a:
rlm@1 3169 case 0x9b:
rlm@1 3170 case 0x9c:
rlm@1 3171 case 0x9d:
rlm@1 3172 case 0x9e:
rlm@1 3173 case 0x9f:
rlm@1 3174 soundEvent(address & 0xFF, b);
rlm@1 3175 break;
rlm@1 3176 default:
rlm@1 3177 // if(address & 1) {
rlm@1 3178 // CPUWriteHalfWord(address-1, (CPUReadHalfWord(address-1)&0x00FF)|((int)b<<8));
rlm@1 3179 // } else
rlm@1 3180 if (address & 1)
rlm@1 3181 CPUUpdateRegister(address & 0x3fe,
rlm@1 3182 ((READ16LE(((u16 *)&ioMem[address & 0x3fe])))
rlm@1 3183 & 0x00FF) |
rlm@1 3184 b << 8);
rlm@1 3185 else
rlm@1 3186 CPUUpdateRegister(address & 0x3fe,
rlm@1 3187 ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b));
rlm@1 3188 }
rlm@1 3189 break;
rlm@1 3190 case 5:
rlm@1 3191 // no need to switch
rlm@1 3192 *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b;
rlm@1 3193 break;
rlm@1 3194 case 6:
rlm@1 3195 // no need to switch
rlm@1 3196 if (address & 0x10000)
rlm@1 3197 *((u16 *)&vram[address & 0x17FFE]) = (b << 8) | b;
rlm@1 3198 else
rlm@1 3199 *((u16 *)&vram[address & 0x1FFFE]) = (b << 8) | b;
rlm@1 3200 break;
rlm@1 3201 case 7:
rlm@1 3202 // no need to switch
rlm@1 3203 *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
rlm@1 3204 break;
rlm@1 3205 case 13:
rlm@1 3206 if (cpuEEPROMEnabled)
rlm@1 3207 {
rlm@1 3208 eepromWrite(address, b);
rlm@1 3209 break;
rlm@1 3210 }
rlm@1 3211 goto unwritable;
rlm@1 3212 case 14:
rlm@1 3213 if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)
rlm@1 3214 {
rlm@1 3215 (*cpuSaveGameFunc)(address, b);
rlm@1 3216 break;
rlm@1 3217 }
rlm@1 3218 // default
rlm@1 3219 default:
rlm@1 3220 unwritable:
rlm@1 3221 #ifdef GBA_LOGGING
rlm@1 3222 if (systemVerbose & VERBOSE_ILLEGAL_WRITE)
rlm@1 3223 {
rlm@1 3224 log("Illegal byte write: %02x to %08x from %08x\n",
rlm@1 3225 b,
rlm@1 3226 address,
rlm@1 3227 armMode ? armNextPC - 4 : armNextPC - 2);
rlm@1 3228 }
rlm@1 3229 #endif
rlm@1 3230 break;
rlm@1 3231 }
rlm@1 3232 }
rlm@1 3233
rlm@1 3234 void CPUWriteByte(u32 address, u8 b)
rlm@1 3235 {
rlm@1 3236 CPUWriteByteWrapped(address, b);
rlm@1 3237 CallRegisteredLuaMemHook(address, 1, b, LUAMEMHOOK_WRITE);
rlm@1 3238 }
rlm@1 3239
rlm@1 3240 bool CPULoadBios(const char *biosFileName, bool useBiosFile)
rlm@1 3241 {
rlm@1 3242 useBios = false;
rlm@1 3243 if (useBiosFile)
rlm@1 3244 {
rlm@1 3245 useBios = utilLoadBIOS(bios, biosFileName, 4);
rlm@1 3246 if (!useBios)
rlm@1 3247 {
rlm@1 3248 systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid GBA BIOS file"));
rlm@1 3249 }
rlm@1 3250 }
rlm@1 3251
rlm@1 3252 if (!useBios)
rlm@1 3253 {
rlm@1 3254 // load internal BIOS
rlm@1 3255 memcpy(bios, myROM, sizeof(myROM));
rlm@1 3256 }
rlm@1 3257
rlm@1 3258 return useBios;
rlm@1 3259 }
rlm@1 3260
rlm@1 3261 void CPUInit()
rlm@1 3262 {
rlm@1 3263 #ifdef WORDS_BIGENDIAN
rlm@1 3264 if (!cpuBiosSwapped)
rlm@1 3265 {
rlm@1 3266 for (unsigned int i = 0; i < sizeof(myROM) / 4; i++)
rlm@1 3267 {
rlm@1 3268 WRITE32LE(&myROM[i], myROM[i]);
rlm@1 3269 }
rlm@1 3270 cpuBiosSwapped = true;
rlm@1 3271 }
rlm@1 3272 #endif
rlm@1 3273 gbaSaveType = 0;
rlm@1 3274 eepromInUse = 0;
rlm@1 3275 saveType = 0;
rlm@1 3276
rlm@1 3277 if (!useBios)
rlm@1 3278 {
rlm@1 3279 // load internal BIOS
rlm@1 3280 memcpy(bios, myROM, sizeof(myROM));
rlm@1 3281 }
rlm@1 3282
rlm@1 3283 biosProtected[0] = 0x00;
rlm@1 3284 biosProtected[1] = 0xf0;
rlm@1 3285 biosProtected[2] = 0x29;
rlm@1 3286 biosProtected[3] = 0xe1;
rlm@1 3287
rlm@1 3288 int i = 0;
rlm@1 3289 for (i = 0; i < 256; i++)
rlm@1 3290 {
rlm@1 3291 int cpuBitSetCount = 0;
rlm@1 3292 int j;
rlm@1 3293 for (j = 0; j < 8; j++)
rlm@1 3294 if (i & (1 << j))
rlm@1 3295 cpuBitSetCount++;
rlm@1 3296 cpuBitsSet[i] = cpuBitSetCount;
rlm@1 3297
rlm@1 3298 for (j = 0; j < 8; j++)
rlm@1 3299 if (i & (1 << j))
rlm@1 3300 break;
rlm@1 3301 cpuLowestBitSet[i] = j;
rlm@1 3302 }
rlm@1 3303
rlm@1 3304 for (i = 0; i < 0x400; i++)
rlm@1 3305 ioReadable[i] = true;
rlm@1 3306 for (i = 0x10; i < 0x48; i++)
rlm@1 3307 ioReadable[i] = false;
rlm@1 3308 for (i = 0x4c; i < 0x50; i++)
rlm@1 3309 ioReadable[i] = false;
rlm@1 3310 for (i = 0x54; i < 0x60; i++)
rlm@1 3311 ioReadable[i] = false;
rlm@1 3312 for (i = 0x8c; i < 0x90; i++)
rlm@1 3313 ioReadable[i] = false;
rlm@1 3314 for (i = 0xa0; i < 0xb8; i++)
rlm@1 3315 ioReadable[i] = false;
rlm@1 3316 for (i = 0xbc; i < 0xc4; i++)
rlm@1 3317 ioReadable[i] = false;
rlm@1 3318 for (i = 0xc8; i < 0xd0; i++)
rlm@1 3319 ioReadable[i] = false;
rlm@1 3320 for (i = 0xd4; i < 0xdc; i++)
rlm@1 3321 ioReadable[i] = false;
rlm@1 3322 for (i = 0xe0; i < 0x100; i++)
rlm@1 3323 ioReadable[i] = false;
rlm@1 3324 for (i = 0x110; i < 0x120; i++)
rlm@1 3325 ioReadable[i] = false;
rlm@1 3326 for (i = 0x12c; i < 0x130; i++)
rlm@1 3327 ioReadable[i] = false;
rlm@1 3328 for (i = 0x138; i < 0x140; i++)
rlm@1 3329 ioReadable[i] = false;
rlm@1 3330 for (i = 0x144; i < 0x150; i++)
rlm@1 3331 ioReadable[i] = false;
rlm@1 3332 for (i = 0x15c; i < 0x200; i++)
rlm@1 3333 ioReadable[i] = false;
rlm@1 3334 for (i = 0x20c; i < 0x300; i++)
rlm@1 3335 ioReadable[i] = false;
rlm@1 3336 for (i = 0x304; i < 0x400; i++)
rlm@1 3337 ioReadable[i] = false;
rlm@1 3338
rlm@1 3339 *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA
rlm@1 3340 *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR
rlm@1 3341
rlm@1 3342 {
rlm@1 3343 int32 origMemoryWaitFetch[16] = { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
rlm@1 3344 int32 origMemoryWaitFetch32[16] = { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
rlm@1 3345 memcpy(memoryWaitFetch, origMemoryWaitFetch, 16 * sizeof(int32));
rlm@1 3346 memcpy(memoryWaitFetch32, origMemoryWaitFetch32, 16 * sizeof(int32));
rlm@1 3347 }
rlm@1 3348 }
rlm@1 3349
rlm@1 3350 void CPUReset(bool userReset)
rlm@1 3351 {
rlm@1 3352 // movie must be closed while opening/creating a movie
rlm@1 3353 if (userReset && VBAMovieRecording())
rlm@1 3354 {
rlm@1 3355 VBAMovieSignalReset();
rlm@1 3356 return;
rlm@1 3357 }
rlm@1 3358
rlm@1 3359 if (!VBAMovieActive())
rlm@1 3360 {
rlm@1 3361 GBASystemCounters.frameCount = 0;
rlm@1 3362 GBASystemCounters.lagCount = 0;
rlm@1 3363 GBASystemCounters.extraCount = 0;
rlm@1 3364 GBASystemCounters.lagged = true;
rlm@1 3365 GBASystemCounters.laggedLast = true;
rlm@1 3366 }
rlm@1 3367
rlm@1 3368 if (gbaSaveType == 0)
rlm@1 3369 {
rlm@1 3370 if (eepromInUse)
rlm@1 3371 gbaSaveType = 3;
rlm@1 3372 else
rlm@1 3373 switch (saveType)
rlm@1 3374 {
rlm@1 3375 case 1:
rlm@1 3376 gbaSaveType = 1;
rlm@1 3377 break;
rlm@1 3378 case 2:
rlm@1 3379 gbaSaveType = 2;
rlm@1 3380 break;
rlm@1 3381 }
rlm@1 3382 }
rlm@1 3383
rlm@1 3384 rtcReset();
rlm@1 3385 // clean registers
rlm@1 3386 memset(&reg[0], 0, sizeof(reg));
rlm@1 3387 // clean OAM
rlm@1 3388 memset(oam, 0, 0x400);
rlm@1 3389 // clean palette
rlm@1 3390 memset(paletteRAM, 0, 0x400);
rlm@1 3391 // clean picture
rlm@1 3392 memset(pix, 0, 4 * 241 * 162);
rlm@1 3393 // clean vram
rlm@1 3394 memset(vram, 0, 0x20000);
rlm@1 3395 // clean io memory
rlm@1 3396 memset(ioMem, 0, 0x400);
rlm@1 3397 // clean RAM
rlm@1 3398 memset(internalRAM, 0, 0x8000); /// FIXME: is it unsafe to erase ALL of this? Even the init code doesn't.
rlm@1 3399 memset(workRAM, 0, 0x40000); /// ditto
rlm@1 3400
rlm@1 3401 DISPCNT = 0x0080;
rlm@1 3402 DISPSTAT = 0x0000;
rlm@1 3403 VCOUNT = 0x0000;
rlm@1 3404 BG0CNT = 0x0000;
rlm@1 3405 BG1CNT = 0x0000;
rlm@1 3406 BG2CNT = 0x0000;
rlm@1 3407 BG3CNT = 0x0000;
rlm@1 3408 BG0HOFS = 0x0000;
rlm@1 3409 BG0VOFS = 0x0000;
rlm@1 3410 BG1HOFS = 0x0000;
rlm@1 3411 BG1VOFS = 0x0000;
rlm@1 3412 BG2HOFS = 0x0000;
rlm@1 3413 BG2VOFS = 0x0000;
rlm@1 3414 BG3HOFS = 0x0000;
rlm@1 3415 BG3VOFS = 0x0000;
rlm@1 3416 BG2PA = 0x0100;
rlm@1 3417 BG2PB = 0x0000;
rlm@1 3418 BG2PC = 0x0000;
rlm@1 3419 BG2PD = 0x0100;
rlm@1 3420 BG2X_L = 0x0000;
rlm@1 3421 BG2X_H = 0x0000;
rlm@1 3422 BG2Y_L = 0x0000;
rlm@1 3423 BG2Y_H = 0x0000;
rlm@1 3424 BG3PA = 0x0100;
rlm@1 3425 BG3PB = 0x0000;
rlm@1 3426 BG3PC = 0x0000;
rlm@1 3427 BG3PD = 0x0100;
rlm@1 3428 BG3X_L = 0x0000;
rlm@1 3429 BG3X_H = 0x0000;
rlm@1 3430 BG3Y_L = 0x0000;
rlm@1 3431 BG3Y_H = 0x0000;
rlm@1 3432 WIN0H = 0x0000;
rlm@1 3433 WIN1H = 0x0000;
rlm@1 3434 WIN0V = 0x0000;
rlm@1 3435 WIN1V = 0x0000;
rlm@1 3436 WININ = 0x0000;
rlm@1 3437 WINOUT = 0x0000;
rlm@1 3438 MOSAIC = 0x0000;
rlm@1 3439 BLDMOD = 0x0000;
rlm@1 3440 COLEV = 0x0000;
rlm@1 3441 COLY = 0x0000;
rlm@1 3442 DM0SAD_L = 0x0000;
rlm@1 3443 DM0SAD_H = 0x0000;
rlm@1 3444 DM0DAD_L = 0x0000;
rlm@1 3445 DM0DAD_H = 0x0000;
rlm@1 3446 DM0CNT_L = 0x0000;
rlm@1 3447 DM0CNT_H = 0x0000;
rlm@1 3448 DM1SAD_L = 0x0000;
rlm@1 3449 DM1SAD_H = 0x0000;
rlm@1 3450 DM1DAD_L = 0x0000;
rlm@1 3451 DM1DAD_H = 0x0000;
rlm@1 3452 DM1CNT_L = 0x0000;
rlm@1 3453 DM1CNT_H = 0x0000;
rlm@1 3454 DM2SAD_L = 0x0000;
rlm@1 3455 DM2SAD_H = 0x0000;
rlm@1 3456 DM2DAD_L = 0x0000;
rlm@1 3457 DM2DAD_H = 0x0000;
rlm@1 3458 DM2CNT_L = 0x0000;
rlm@1 3459 DM2CNT_H = 0x0000;
rlm@1 3460 DM3SAD_L = 0x0000;
rlm@1 3461 DM3SAD_H = 0x0000;
rlm@1 3462 DM3DAD_L = 0x0000;
rlm@1 3463 DM3DAD_H = 0x0000;
rlm@1 3464 DM3CNT_L = 0x0000;
rlm@1 3465 DM3CNT_H = 0x0000;
rlm@1 3466 TM0D = 0x0000;
rlm@1 3467 TM0CNT = 0x0000;
rlm@1 3468 TM1D = 0x0000;
rlm@1 3469 TM1CNT = 0x0000;
rlm@1 3470 TM2D = 0x0000;
rlm@1 3471 TM2CNT = 0x0000;
rlm@1 3472 TM3D = 0x0000;
rlm@1 3473 TM3CNT = 0x0000;
rlm@1 3474 P1 = 0x03FF;
rlm@1 3475 IE = 0x0000;
rlm@1 3476 IF = 0x0000;
rlm@1 3477 IME = 0x0000;
rlm@1 3478
rlm@1 3479 armMode = 0x1F;
rlm@1 3480
rlm@1 3481 if (cpuIsMultiBoot)
rlm@1 3482 {
rlm@1 3483 reg[13].I = 0x03007F00;
rlm@1 3484 reg[15].I = 0x02000000;
rlm@1 3485 reg[16].I = 0x00000000;
rlm@1 3486 reg[R13_IRQ].I = 0x03007FA0;
rlm@1 3487 reg[R13_SVC].I = 0x03007FE0;
rlm@1 3488 armIrqEnable = true;
rlm@1 3489 }
rlm@1 3490 else
rlm@1 3491 {
rlm@1 3492 if (useBios && !skipBios)
rlm@1 3493 {
rlm@1 3494 reg[15].I = 0x00000000;
rlm@1 3495 armMode = 0x13;
rlm@1 3496 armIrqEnable = false;
rlm@1 3497 }
rlm@1 3498 else
rlm@1 3499 {
rlm@1 3500 reg[13].I = 0x03007F00;
rlm@1 3501 reg[15].I = 0x08000000;
rlm@1 3502 reg[16].I = 0x00000000;
rlm@1 3503 reg[R13_IRQ].I = 0x03007FA0;
rlm@1 3504 reg[R13_SVC].I = 0x03007FE0;
rlm@1 3505 armIrqEnable = true;
rlm@1 3506 }
rlm@1 3507 }
rlm@1 3508 armState = true;
rlm@1 3509 C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false;
rlm@1 3510 UPDATE_REG(0x00, DISPCNT);
rlm@1 3511 UPDATE_REG(0x20, BG2PA);
rlm@1 3512 UPDATE_REG(0x26, BG2PD);
rlm@1 3513 UPDATE_REG(0x30, BG3PA);
rlm@1 3514 UPDATE_REG(0x36, BG3PD);
rlm@1 3515 UPDATE_REG(0x130, P1);
rlm@1 3516 UPDATE_REG(0x88, 0x200);
rlm@1 3517
rlm@1 3518 // disable FIQ
rlm@1 3519 reg[16].I |= 0x40;
rlm@1 3520 CPUUpdateCPSR();
rlm@1 3521
rlm@1 3522 armNextPC = reg[15].I;
rlm@1 3523 reg[15].I += 4;
rlm@1 3524
rlm@1 3525 // reset internal state
rlm@1 3526 holdState = false;
rlm@1 3527 holdType = 0;
rlm@1 3528
rlm@1 3529 biosProtected[0] = 0x00;
rlm@1 3530 biosProtected[1] = 0xf0;
rlm@1 3531 biosProtected[2] = 0x29;
rlm@1 3532 biosProtected[3] = 0xe1;
rlm@1 3533
rlm@1 3534 BIOS_RegisterRamReset();
rlm@1 3535
rlm@1 3536 lcdTicks = 960;
rlm@1 3537 timer0On = false;
rlm@1 3538 timer0Ticks = 0;
rlm@1 3539 timer0Reload = 0;
rlm@1 3540 timer0ClockReload = 0;
rlm@1 3541 timer1On = false;
rlm@1 3542 timer1Ticks = 0;
rlm@1 3543 timer1Reload = 0;
rlm@1 3544 timer1ClockReload = 0;
rlm@1 3545 timer2On = false;
rlm@1 3546 timer2Ticks = 0;
rlm@1 3547 timer2Reload = 0;
rlm@1 3548 timer2ClockReload = 0;
rlm@1 3549 timer3On = false;
rlm@1 3550 timer3Ticks = 0;
rlm@1 3551 timer3Reload = 0;
rlm@1 3552 timer3ClockReload = 0;
rlm@1 3553 dma0Source = 0;
rlm@1 3554 dma0Dest = 0;
rlm@1 3555 dma1Source = 0;
rlm@1 3556 dma1Dest = 0;
rlm@1 3557 dma2Source = 0;
rlm@1 3558 dma2Dest = 0;
rlm@1 3559 dma3Source = 0;
rlm@1 3560 dma3Dest = 0;
rlm@1 3561 cpuSaveGameFunc = flashSaveDecide;
rlm@1 3562 renderLine = mode0RenderLine;
rlm@1 3563 fxOn = false;
rlm@1 3564 windowOn = false;
rlm@1 3565 frameSkipCount = 0;
rlm@1 3566 saveType = 0;
rlm@1 3567 layerEnable = DISPCNT & layerSettings;
rlm@1 3568
rlm@1 3569 CPUUpdateRenderBuffers(true);
rlm@1 3570
rlm@1 3571 for (int i = 0; i < 256; i++)
rlm@1 3572 {
rlm@1 3573 map[i].address = (u8 *)&dummyAddress;
rlm@1 3574 map[i].mask = 0;
rlm@1 3575 }
rlm@1 3576
rlm@1 3577 map[0].address = bios;
rlm@1 3578 map[0].mask = 0x3FFF;
rlm@1 3579 map[2].address = workRAM;
rlm@1 3580 map[2].mask = 0x3FFFF;
rlm@1 3581 map[3].address = internalRAM;
rlm@1 3582 map[3].mask = 0x7FFF;
rlm@1 3583 map[4].address = ioMem;
rlm@1 3584 map[4].mask = 0x3FF;
rlm@1 3585 map[5].address = paletteRAM;
rlm@1 3586 map[5].mask = 0x3FF;
rlm@1 3587 map[6].address = vram;
rlm@1 3588 map[6].mask = 0x1FFFF;
rlm@1 3589 map[7].address = oam;
rlm@1 3590 map[7].mask = 0x3FF;
rlm@1 3591 map[8].address = rom;
rlm@1 3592 map[8].mask = 0x1FFFFFF;
rlm@1 3593 map[9].address = rom;
rlm@1 3594 map[9].mask = 0x1FFFFFF;
rlm@1 3595 map[10].address = rom;
rlm@1 3596 map[10].mask = 0x1FFFFFF;
rlm@1 3597 map[12].address = rom;
rlm@1 3598 map[12].mask = 0x1FFFFFF;
rlm@1 3599 map[14].address = flashSaveMemory;
rlm@1 3600 map[14].mask = 0xFFFF;
rlm@1 3601
rlm@1 3602 eepromReset();
rlm@1 3603 flashReset();
rlm@1 3604
rlm@1 3605 soundReset();
rlm@1 3606
rlm@1 3607 CPUUpdateWindow0();
rlm@1 3608 CPUUpdateWindow1();
rlm@1 3609
rlm@1 3610 // make sure registers are correctly initialized if not using BIOS
rlm@1 3611 if (!useBios)
rlm@1 3612 {
rlm@1 3613 if (cpuIsMultiBoot)
rlm@1 3614 BIOS_RegisterRamReset(0xfe);
rlm@1 3615 else
rlm@1 3616 BIOS_RegisterRamReset(0xff);
rlm@1 3617 }
rlm@1 3618 else
rlm@1 3619 {
rlm@1 3620 if (cpuIsMultiBoot)
rlm@1 3621 BIOS_RegisterRamReset(0xfe);
rlm@1 3622 }
rlm@1 3623
rlm@1 3624 switch (cpuSaveType)
rlm@1 3625 {
rlm@1 3626 case 0: // automatic
rlm@1 3627 cpuSramEnabled = true;
rlm@1 3628 cpuFlashEnabled = true;
rlm@1 3629 cpuEEPROMEnabled = true;
rlm@1 3630 cpuEEPROMSensorEnabled = false;
rlm@1 3631 break;
rlm@1 3632 case 1: // EEPROM
rlm@1 3633 cpuSramEnabled = false;
rlm@1 3634 cpuFlashEnabled = false;
rlm@1 3635 cpuEEPROMEnabled = true;
rlm@1 3636 cpuEEPROMSensorEnabled = false;
rlm@1 3637 break;
rlm@1 3638 case 2: // SRAM
rlm@1 3639 cpuSramEnabled = true;
rlm@1 3640 cpuFlashEnabled = false;
rlm@1 3641 cpuEEPROMEnabled = false;
rlm@1 3642 cpuEEPROMSensorEnabled = false;
rlm@1 3643 cpuSaveGameFunc = sramWrite;
rlm@1 3644 break;
rlm@1 3645 case 3: // FLASH
rlm@1 3646 cpuSramEnabled = false;
rlm@1 3647 cpuFlashEnabled = true;
rlm@1 3648 cpuEEPROMEnabled = false;
rlm@1 3649 cpuEEPROMSensorEnabled = false;
rlm@1 3650 cpuSaveGameFunc = flashWrite;
rlm@1 3651 break;
rlm@1 3652 case 4: // EEPROM+Sensor
rlm@1 3653 cpuSramEnabled = false;
rlm@1 3654 cpuFlashEnabled = false;
rlm@1 3655 cpuEEPROMEnabled = true;
rlm@1 3656 cpuEEPROMSensorEnabled = true;
rlm@1 3657 break;
rlm@1 3658 case 5: // NONE
rlm@1 3659 cpuSramEnabled = false;
rlm@1 3660 cpuFlashEnabled = false;
rlm@1 3661 cpuEEPROMEnabled = false;
rlm@1 3662 cpuEEPROMSensorEnabled = false;
rlm@1 3663 break;
rlm@1 3664 }
rlm@1 3665
rlm@1 3666 systemResetSensor();
rlm@1 3667
rlm@1 3668 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
rlm@1 3669
rlm@1 3670 gbaLastTime = systemGetClock();
rlm@1 3671 gbaFrameCount = 0;
rlm@1 3672
rlm@1 3673 systemRefreshScreen();
rlm@1 3674 }
rlm@1 3675
rlm@1 3676 void CPUInterrupt()
rlm@1 3677 {
rlm@1 3678 u32 PC = reg[15].I;
rlm@1 3679 bool savedState = armState;
rlm@1 3680 CPUSwitchMode(0x12, true, false);
rlm@1 3681 reg[14].I = PC;
rlm@1 3682 if (!savedState)
rlm@1 3683 reg[14].I += 2;
rlm@1 3684 reg[15].I = 0x18;
rlm@1 3685 armState = true;
rlm@1 3686 armIrqEnable = false;
rlm@1 3687
rlm@1 3688 armNextPC = reg[15].I;
rlm@1 3689 reg[15].I += 4;
rlm@1 3690
rlm@1 3691 // if(!holdState)
rlm@1 3692 biosProtected[0] = 0x02;
rlm@1 3693 biosProtected[1] = 0xc0;
rlm@1 3694 biosProtected[2] = 0x5e;
rlm@1 3695 biosProtected[3] = 0xe5;
rlm@1 3696 }
rlm@1 3697
rlm@1 3698 void TogglePrefetchHack()
rlm@1 3699 {
rlm@1 3700 memLagTempEnabled = !memLagTempEnabled;
rlm@1 3701
rlm@1 3702 if (emulating)
rlm@1 3703 {
rlm@1 3704 extern bool8 prefetchActive, prefetchPrevActive, prefetchApplies;
rlm@1 3705 if (prefetchApplies && prefetchActive == memLagTempEnabled)
rlm@1 3706 {
rlm@1 3707 prefetchActive = !prefetchActive;
rlm@1 3708 //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
rlm@1 3709 //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
rlm@1 3710 extern int32 memoryWaitFetch [16];
rlm@1 3711 if (prefetchActive)
rlm@1 3712 memoryWaitFetch[8]--;
rlm@1 3713 else
rlm@1 3714 memoryWaitFetch[8]++;
rlm@1 3715 prefetchPrevActive = prefetchActive;
rlm@1 3716 }
rlm@1 3717 }
rlm@1 3718 }
rlm@1 3719
rlm@1 3720 void SetPrefetchHack(bool set)
rlm@1 3721 {
rlm@1 3722 if ((bool)memLagTempEnabled == set)
rlm@1 3723 TogglePrefetchHack();
rlm@1 3724 }
rlm@1 3725
rlm@1 3726 #ifdef SDL
rlm@1 3727 void log(const char *defaultMsg, ...)
rlm@1 3728 {
rlm@1 3729 char buffer[2048];
rlm@1 3730 va_list valist;
rlm@1 3731
rlm@1 3732 va_start(valist, defaultMsg);
rlm@1 3733 vsprintf(buffer, defaultMsg, valist);
rlm@1 3734
rlm@1 3735 if (out == NULL)
rlm@1 3736 {
rlm@1 3737 out = fopen("trace.log", "w");
rlm@1 3738 }
rlm@1 3739
rlm@1 3740 fputs(buffer, out);
rlm@1 3741
rlm@1 3742 va_end(valist);
rlm@1 3743 }
rlm@1 3744
rlm@1 3745 #else
rlm@1 3746 extern void winlog(const char *, ...);
rlm@1 3747 #endif
rlm@1 3748
rlm@1 3749 void CPULoop(int _ticks)
rlm@1 3750 {
rlm@1 3751 int32 ticks = _ticks;
rlm@1 3752 int32 clockTicks;
rlm@1 3753 int32 cpuLoopTicks = 0;
rlm@1 3754 int32 timerOverflow = 0;
rlm@1 3755 // variables used by the CPU core
rlm@1 3756
rlm@1 3757 extCpuLoopTicks = &cpuLoopTicks;
rlm@1 3758 extClockTicks = &clockTicks;
rlm@1 3759 extTicks = &ticks;
rlm@1 3760
rlm@1 3761 cpuLoopTicks = CPUUpdateTicks();
rlm@1 3762 if (cpuLoopTicks > ticks)
rlm@1 3763 {
rlm@1 3764 cpuLoopTicks = ticks;
rlm@1 3765 cpuSavedTicks = ticks;
rlm@1 3766 }
rlm@1 3767
rlm@1 3768 if (intState)
rlm@1 3769 {
rlm@1 3770 cpuLoopTicks = 5;
rlm@1 3771 cpuSavedTicks = 5;
rlm@1 3772 }
rlm@1 3773
rlm@1 3774 if (newFrame)
rlm@1 3775 {
rlm@1 3776 extern void VBAOnExitingFrameBoundary();
rlm@1 3777 VBAOnExitingFrameBoundary();
rlm@1 3778
rlm@1 3779 // update joystick information
rlm@1 3780 systemReadJoypads();
rlm@1 3781
rlm@1 3782 u32 joy = systemGetJoypad(0, cpuEEPROMSensorEnabled);
rlm@1 3783
rlm@1 3784 // if (cpuEEPROMSensorEnabled)
rlm@1 3785 // systemUpdateMotionSensor(0);
rlm@1 3786
rlm@1 3787 P1 = 0x03FF ^ (joy & 0x3FF);
rlm@1 3788 UPDATE_REG(0x130, P1);
rlm@1 3789 u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132]));
rlm@1 3790 // this seems wrong, but there are cases where the game
rlm@1 3791 // can enter the stop state without requesting an IRQ from
rlm@1 3792 // the joypad.
rlm@1 3793 if ((P1CNT & 0x4000) || stopState)
rlm@1 3794 {
rlm@1 3795 u16 p1 = (0x3FF ^ P1) & 0x3FF;
rlm@1 3796 if (P1CNT & 0x8000)
rlm@1 3797 {
rlm@1 3798 if (p1 == (P1CNT & 0x3FF))
rlm@1 3799 {
rlm@1 3800 IF |= 0x1000;
rlm@1 3801 UPDATE_REG(0x202, IF);
rlm@1 3802 }
rlm@1 3803 }
rlm@1 3804 else
rlm@1 3805 {
rlm@1 3806 if (p1 & P1CNT)
rlm@1 3807 {
rlm@1 3808 IF |= 0x1000;
rlm@1 3809 UPDATE_REG(0x202, IF);
rlm@1 3810 }
rlm@1 3811 }
rlm@1 3812 }
rlm@1 3813
rlm@1 3814 // HACK: some special "buttons"
rlm@1 3815 extButtons = (joy >> 18);
rlm@1 3816 speedup = (extButtons & 1) != 0;
rlm@1 3817
rlm@1 3818 VBAMovieResetIfRequested();
rlm@1 3819
rlm@1 3820 CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION);
rlm@1 3821
rlm@1 3822 newFrame = false;
rlm@1 3823 }
rlm@1 3824
rlm@1 3825 for (;; )
rlm@1 3826 {
rlm@1 3827 #ifndef FINAL_VERSION
rlm@1 3828 if (systemDebug)
rlm@1 3829 {
rlm@1 3830 if (systemDebug >= 10 && !holdState)
rlm@1 3831 {
rlm@1 3832 CPUUpdateCPSR();
rlm@1 3833 sprintf(
rlm@1 3834 buffer,
rlm@1 3835 "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x"
rlm@1 3836 "R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
rlm@1 3837 reg[0].I,
rlm@1 3838 reg[1].I,
rlm@1 3839 reg[2].I,
rlm@1 3840 reg[3].I,
rlm@1 3841 reg[4].I,
rlm@1 3842 reg[5].I,
rlm@1 3843 reg[6].I,
rlm@1 3844 reg[7].I,
rlm@1 3845 reg[8].I,
rlm@1 3846 reg[9].I,
rlm@1 3847 reg[10].I,
rlm@1 3848 reg[11].I,
rlm@1 3849 reg[12].I,
rlm@1 3850 reg[13].I,
rlm@1 3851 reg[14].I,
rlm@1 3852 reg[15].I,
rlm@1 3853 reg[16].I,
rlm@1 3854 reg[17].I);
rlm@1 3855 #ifdef SDL
rlm@1 3856 log(buffer);
rlm@1 3857 #else
rlm@1 3858 winlog(buffer);
rlm@1 3859 #endif
rlm@1 3860 }
rlm@1 3861 else if (!holdState)
rlm@1 3862 {
rlm@1 3863 sprintf(buffer, "PC=%08x\n", armNextPC);
rlm@1 3864 #ifdef SDL
rlm@1 3865 log(buffer);
rlm@1 3866 #else
rlm@1 3867 winlog(buffer);
rlm@1 3868 #endif
rlm@1 3869 }
rlm@1 3870 }
rlm@1 3871 #endif
rlm@1 3872
rlm@1 3873 if (!holdState)
rlm@1 3874 {
rlm@1 3875 if (armState)
rlm@1 3876 {
rlm@1 3877 CallRegisteredLuaMemHook(armNextPC, 4, CPUReadMemoryQuick(armNextPC), LUAMEMHOOK_EXEC);
rlm@1 3878 #include "arm-new.h"
rlm@1 3879 }
rlm@1 3880 else
rlm@1 3881 {
rlm@1 3882 CallRegisteredLuaMemHook(armNextPC, 2, CPUReadHalfWordQuick(armNextPC), LUAMEMHOOK_EXEC);
rlm@1 3883 #include "thumb.h"
rlm@1 3884 }
rlm@1 3885 }
rlm@1 3886 else
rlm@1 3887 {
rlm@1 3888 clockTicks = lcdTicks;
rlm@1 3889
rlm@1 3890 if (soundTicks < clockTicks)
rlm@1 3891 clockTicks = soundTicks;
rlm@1 3892
rlm@1 3893 if (timer0On && (timer0Ticks < clockTicks))
rlm@1 3894 {
rlm@1 3895 clockTicks = timer0Ticks;
rlm@1 3896 }
rlm@1 3897 if (timer1On && (timer1Ticks < clockTicks))
rlm@1 3898 {
rlm@1 3899 clockTicks = timer1Ticks;
rlm@1 3900 }
rlm@1 3901 if (timer2On && (timer2Ticks < clockTicks))
rlm@1 3902 {
rlm@1 3903 clockTicks = timer2Ticks;
rlm@1 3904 }
rlm@1 3905 if (timer3On && (timer3Ticks < clockTicks))
rlm@1 3906 {
rlm@1 3907 clockTicks = timer3Ticks;
rlm@1 3908 }
rlm@1 3909 #ifdef PROFILING
rlm@1 3910 if (profilingTicksReload != 0)
rlm@1 3911 {
rlm@1 3912 if (profilingTicks < clockTicks)
rlm@1 3913 {
rlm@1 3914 clockTicks = profilingTicks;
rlm@1 3915 }
rlm@1 3916 }
rlm@1 3917 #endif
rlm@1 3918 }
rlm@1 3919
rlm@1 3920 cpuLoopTicks -= clockTicks;
rlm@1 3921 if ((cpuLoopTicks <= 0))
rlm@1 3922 {
rlm@1 3923 if (cpuSavedTicks)
rlm@1 3924 {
rlm@1 3925 clockTicks = cpuSavedTicks; // + cpuLoopTicks;
rlm@1 3926 }
rlm@1 3927 cpuDmaTicksToUpdate = -cpuLoopTicks;
rlm@1 3928
rlm@1 3929 updateLoop:
rlm@1 3930 lcdTicks -= clockTicks;
rlm@1 3931
rlm@1 3932 if (lcdTicks <= 0)
rlm@1 3933 {
rlm@1 3934 if (DISPSTAT & 1) // V-BLANK
rlm@1 3935 { // if in V-Blank mode, keep computing...
rlm@1 3936 if (DISPSTAT & 2)
rlm@1 3937 {
rlm@1 3938 lcdTicks += 960;
rlm@1 3939 VCOUNT++;
rlm@1 3940 UPDATE_REG(0x06, VCOUNT);
rlm@1 3941 DISPSTAT &= 0xFFFD;
rlm@1 3942 UPDATE_REG(0x04, DISPSTAT);
rlm@1 3943 CPUCompareVCOUNT();
rlm@1 3944 }
rlm@1 3945 else
rlm@1 3946 {
rlm@1 3947 lcdTicks += 272;
rlm@1 3948 DISPSTAT |= 2;
rlm@1 3949 UPDATE_REG(0x04, DISPSTAT);
rlm@1 3950 if (DISPSTAT & 16)
rlm@1 3951 {
rlm@1 3952 IF |= 2;
rlm@1 3953 UPDATE_REG(0x202, IF);
rlm@1 3954 }
rlm@1 3955 }
rlm@1 3956
rlm@1 3957 if (VCOUNT >= 228)
rlm@1 3958 {
rlm@1 3959 DISPSTAT &= 0xFFFC;
rlm@1 3960 UPDATE_REG(0x04, DISPSTAT);
rlm@1 3961 VCOUNT = 0;
rlm@1 3962 UPDATE_REG(0x06, VCOUNT);
rlm@1 3963 CPUCompareVCOUNT();
rlm@1 3964 }
rlm@1 3965 }
rlm@1 3966 else
rlm@1 3967 {
rlm@1 3968 int framesToSkip = systemFramesToSkip();
rlm@1 3969
rlm@1 3970 if (DISPSTAT & 2)
rlm@1 3971 {
rlm@1 3972 // if in H-Blank, leave it and move to drawing mode
rlm@1 3973 VCOUNT++;
rlm@1 3974 UPDATE_REG(0x06, VCOUNT);
rlm@1 3975
rlm@1 3976 lcdTicks += 960;
rlm@1 3977 DISPSTAT &= 0xFFFD;
rlm@1 3978 if (VCOUNT == 160)
rlm@1 3979 {
rlm@1 3980 DISPSTAT |= 1;
rlm@1 3981 DISPSTAT &= 0xFFFD;
rlm@1 3982 UPDATE_REG(0x04, DISPSTAT);
rlm@1 3983 if (DISPSTAT & 0x0008)
rlm@1 3984 {
rlm@1 3985 IF |= 1;
rlm@1 3986 UPDATE_REG(0x202, IF);
rlm@1 3987 }
rlm@1 3988 CPUCheckDMA(1, 0x0f);
rlm@1 3989
rlm@1 3990 systemFrame();
rlm@1 3991
rlm@1 3992 ++gbaFrameCount;
rlm@1 3993 u32 gbaCurrentTime = systemGetClock();
rlm@1 3994 if (gbaCurrentTime - gbaLastTime >= 1000)
rlm@1 3995 {
rlm@1 3996 systemShowSpeed(int(float(gbaFrameCount) * 100000 / (float(gbaCurrentTime - gbaLastTime) * 60) + .5f));
rlm@1 3997 gbaLastTime = gbaCurrentTime;
rlm@1 3998 gbaFrameCount = 0;
rlm@1 3999 }
rlm@1 4000
rlm@1 4001 ++GBASystemCounters.frameCount;
rlm@1 4002 if (GBASystemCounters.lagged)
rlm@1 4003 {
rlm@1 4004 ++GBASystemCounters.lagCount;
rlm@1 4005 }
rlm@1 4006 GBASystemCounters.laggedLast = GBASystemCounters.lagged;
rlm@1 4007 GBASystemCounters.lagged = true;
rlm@1 4008
rlm@1 4009 if (cheatsEnabled)
rlm@1 4010 cheatsCheckKeys(P1 ^ 0x3FF, extButtons);
rlm@1 4011
rlm@1 4012 extern void VBAOnEnteringFrameBoundary();
rlm@1 4013 VBAOnEnteringFrameBoundary();
rlm@1 4014
rlm@1 4015 newFrame = true;
rlm@1 4016
rlm@1 4017 pauseAfterFrameAdvance = systemPauseOnFrame();
rlm@1 4018
rlm@1 4019 if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance)
rlm@1 4020 {
rlm@1 4021 systemRenderFrame();
rlm@1 4022 frameSkipCount = 0;
rlm@1 4023
rlm@1 4024 bool capturePressed = (extButtons & 2) != 0;
rlm@1 4025 if (capturePressed && !capturePrevious)
rlm@1 4026 {
rlm@1 4027 captureNumber = systemScreenCapture(captureNumber);
rlm@1 4028 }
rlm@1 4029 capturePrevious = capturePressed && !pauseAfterFrameAdvance;
rlm@1 4030 }
rlm@1 4031 else
rlm@1 4032 {
rlm@1 4033 ++frameSkipCount;
rlm@1 4034 }
rlm@1 4035
rlm@1 4036 if (pauseAfterFrameAdvance)
rlm@1 4037 {
rlm@1 4038 systemSetPause(true);
rlm@1 4039 }
rlm@1 4040 }
rlm@1 4041
rlm@1 4042 UPDATE_REG(0x04, DISPSTAT);
rlm@1 4043 CPUCompareVCOUNT();
rlm@1 4044 }
rlm@1 4045 else
rlm@1 4046 {
rlm@1 4047 if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance)
rlm@1 4048 {
rlm@1 4049 (*renderLine)();
rlm@1 4050
rlm@1 4051 switch (systemColorDepth)
rlm@1 4052 {
rlm@1 4053 case 16:
rlm@1 4054 {
rlm@1 4055 u16 *dest = (u16 *)pix + 242 * (VCOUNT + 1);
rlm@1 4056 for (int x = 0; x < 240; )
rlm@1 4057 {
rlm@1 4058 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4059 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4060 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4061 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4062
rlm@1 4063 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4064 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4065 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4066 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4067
rlm@1 4068 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4069 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4070 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4071 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4072
rlm@1 4073 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4074 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4075 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4076 *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
rlm@1 4077 }
rlm@1 4078 // for filters that read past the screen
rlm@1 4079 *dest++ = 0;
rlm@1 4080 break;
rlm@1 4081 }
rlm@1 4082 case 24:
rlm@1 4083 {
rlm@1 4084 u8 *dest = (u8 *)pix + 240 * VCOUNT * 3;
rlm@1 4085 for (int x = 0; x < 240; )
rlm@1 4086 {
rlm@1 4087 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4088 dest += 3;
rlm@1 4089 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4090 dest += 3;
rlm@1 4091 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4092 dest += 3;
rlm@1 4093 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4094 dest += 3;
rlm@1 4095
rlm@1 4096 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4097 dest += 3;
rlm@1 4098 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4099 dest += 3;
rlm@1 4100 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4101 dest += 3;
rlm@1 4102 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4103 dest += 3;
rlm@1 4104
rlm@1 4105 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4106 dest += 3;
rlm@1 4107 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4108 dest += 3;
rlm@1 4109 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4110 dest += 3;
rlm@1 4111 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4112 dest += 3;
rlm@1 4113
rlm@1 4114 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4115 dest += 3;
rlm@1 4116 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4117 dest += 3;
rlm@1 4118 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4119 dest += 3;
rlm@1 4120 *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4121 dest += 3;
rlm@1 4122 }
rlm@1 4123 break;
rlm@1 4124 }
rlm@1 4125 case 32:
rlm@1 4126 {
rlm@1 4127 u32 *dest = (u32 *)pix + 241 * (VCOUNT + 1);
rlm@1 4128 for (int x = 0; x < 240; )
rlm@1 4129 {
rlm@1 4130 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4131 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4132 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4133 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4134
rlm@1 4135 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4136 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4137 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4138 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4139
rlm@1 4140 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4141 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4142 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4143 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4144
rlm@1 4145 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4146 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4147 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4148 *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
rlm@1 4149 }
rlm@1 4150 break;
rlm@1 4151 }
rlm@1 4152 }
rlm@1 4153 }
rlm@1 4154 // entering H-Blank
rlm@1 4155 DISPSTAT |= 2;
rlm@1 4156 UPDATE_REG(0x04, DISPSTAT);
rlm@1 4157 lcdTicks += 272;
rlm@1 4158 CPUCheckDMA(2, 0x0f);
rlm@1 4159 if (DISPSTAT & 16)
rlm@1 4160 {
rlm@1 4161 IF |= 2;
rlm@1 4162 UPDATE_REG(0x202, IF);
rlm@1 4163 }
rlm@1 4164 }
rlm@1 4165 }
rlm@1 4166 }
rlm@1 4167
rlm@1 4168 if (!stopState)
rlm@1 4169 {
rlm@1 4170 if (timer0On)
rlm@1 4171 {
rlm@1 4172 if (timer0ClockReload == 1)
rlm@1 4173 {
rlm@1 4174 u32 tm0d = TM0D + clockTicks;
rlm@1 4175 if (tm0d > 0xffff)
rlm@1 4176 {
rlm@1 4177 tm0d += timer0Reload;
rlm@1 4178 timerOverflow |= 1;
rlm@1 4179 soundTimerOverflow(0);
rlm@1 4180 if (TM0CNT & 0x40)
rlm@1 4181 {
rlm@1 4182 IF |= 0x08;
rlm@1 4183 UPDATE_REG(0x202, IF);
rlm@1 4184 }
rlm@1 4185 }
rlm@1 4186 TM0D = tm0d & 0xFFFF;
rlm@1 4187 timer0Ticks = 0x10000 - TM0D;
rlm@1 4188 UPDATE_REG(0x100, TM0D);
rlm@1 4189 }
rlm@1 4190 else
rlm@1 4191 {
rlm@1 4192 timer0Ticks -= clockTicks;
rlm@1 4193 if (timer0Ticks <= 0)
rlm@1 4194 {
rlm@1 4195 timer0Ticks += timer0ClockReload;
rlm@1 4196 TM0D++;
rlm@1 4197 if (TM0D == 0)
rlm@1 4198 {
rlm@1 4199 TM0D = timer0Reload;
rlm@1 4200 timerOverflow |= 1;
rlm@1 4201 soundTimerOverflow(0);
rlm@1 4202 if (TM0CNT & 0x40)
rlm@1 4203 {
rlm@1 4204 IF |= 0x08;
rlm@1 4205 UPDATE_REG(0x202, IF);
rlm@1 4206 }
rlm@1 4207 }
rlm@1 4208 UPDATE_REG(0x100, TM0D);
rlm@1 4209 }
rlm@1 4210 }
rlm@1 4211 }
rlm@1 4212
rlm@1 4213 if (timer1On)
rlm@1 4214 {
rlm@1 4215 if (TM1CNT & 4)
rlm@1 4216 {
rlm@1 4217 if (timerOverflow & 1)
rlm@1 4218 {
rlm@1 4219 TM1D++;
rlm@1 4220 if (TM1D == 0)
rlm@1 4221 {
rlm@1 4222 TM1D += timer1Reload;
rlm@1 4223 timerOverflow |= 2;
rlm@1 4224 soundTimerOverflow(1);
rlm@1 4225 if (TM1CNT & 0x40)
rlm@1 4226 {
rlm@1 4227 IF |= 0x10;
rlm@1 4228 UPDATE_REG(0x202, IF);
rlm@1 4229 }
rlm@1 4230 }
rlm@1 4231 UPDATE_REG(0x104, TM1D);
rlm@1 4232 }
rlm@1 4233 }
rlm@1 4234 else
rlm@1 4235 {
rlm@1 4236 if (timer1ClockReload == 1)
rlm@1 4237 {
rlm@1 4238 u32 tm1d = TM1D + clockTicks;
rlm@1 4239 if (tm1d > 0xffff)
rlm@1 4240 {
rlm@1 4241 tm1d += timer1Reload;
rlm@1 4242 timerOverflow |= 2;
rlm@1 4243 soundTimerOverflow(1);
rlm@1 4244 if (TM1CNT & 0x40)
rlm@1 4245 {
rlm@1 4246 IF |= 0x10;
rlm@1 4247 UPDATE_REG(0x202, IF);
rlm@1 4248 }
rlm@1 4249 }
rlm@1 4250 TM1D = tm1d & 0xFFFF;
rlm@1 4251 timer1Ticks = 0x10000 - TM1D;
rlm@1 4252 UPDATE_REG(0x104, TM1D);
rlm@1 4253 }
rlm@1 4254 else
rlm@1 4255 {
rlm@1 4256 timer1Ticks -= clockTicks;
rlm@1 4257 if (timer1Ticks <= 0)
rlm@1 4258 {
rlm@1 4259 timer1Ticks += timer1ClockReload;
rlm@1 4260 TM1D++;
rlm@1 4261
rlm@1 4262 if (TM1D == 0)
rlm@1 4263 {
rlm@1 4264 TM1D = timer1Reload;
rlm@1 4265 timerOverflow |= 2;
rlm@1 4266 soundTimerOverflow(1);
rlm@1 4267 if (TM1CNT & 0x40)
rlm@1 4268 {
rlm@1 4269 IF |= 0x10;
rlm@1 4270 UPDATE_REG(0x202, IF);
rlm@1 4271 }
rlm@1 4272 }
rlm@1 4273 UPDATE_REG(0x104, TM1D);
rlm@1 4274 }
rlm@1 4275 }
rlm@1 4276 }
rlm@1 4277 }
rlm@1 4278
rlm@1 4279 if (timer2On)
rlm@1 4280 {
rlm@1 4281 if (TM2CNT & 4)
rlm@1 4282 {
rlm@1 4283 if (timerOverflow & 2)
rlm@1 4284 {
rlm@1 4285 TM2D++;
rlm@1 4286 if (TM2D == 0)
rlm@1 4287 {
rlm@1 4288 TM2D += timer2Reload;
rlm@1 4289 timerOverflow |= 4;
rlm@1 4290 if (TM2CNT & 0x40)
rlm@1 4291 {
rlm@1 4292 IF |= 0x20;
rlm@1 4293 UPDATE_REG(0x202, IF);
rlm@1 4294 }
rlm@1 4295 }
rlm@1 4296 UPDATE_REG(0x108, TM2D);
rlm@1 4297 }
rlm@1 4298 }
rlm@1 4299 else
rlm@1 4300 {
rlm@1 4301 if (timer2ClockReload == 1)
rlm@1 4302 {
rlm@1 4303 u32 tm2d = TM2D + clockTicks;
rlm@1 4304 if (tm2d > 0xffff)
rlm@1 4305 {
rlm@1 4306 tm2d += timer2Reload;
rlm@1 4307 timerOverflow |= 4;
rlm@1 4308 if (TM2CNT & 0x40)
rlm@1 4309 {
rlm@1 4310 IF |= 0x20;
rlm@1 4311 UPDATE_REG(0x202, IF);
rlm@1 4312 }
rlm@1 4313 }
rlm@1 4314 TM2D = tm2d & 0xFFFF;
rlm@1 4315 timer2Ticks = 0x10000 - TM2D;
rlm@1 4316 UPDATE_REG(0x108, TM2D);
rlm@1 4317 }
rlm@1 4318 else
rlm@1 4319 {
rlm@1 4320 timer2Ticks -= clockTicks;
rlm@1 4321 if (timer2Ticks <= 0)
rlm@1 4322 {
rlm@1 4323 timer2Ticks += timer2ClockReload;
rlm@1 4324 TM2D++;
rlm@1 4325
rlm@1 4326 if (TM2D == 0)
rlm@1 4327 {
rlm@1 4328 TM2D = timer2Reload;
rlm@1 4329 timerOverflow |= 4;
rlm@1 4330 if (TM2CNT & 0x40)
rlm@1 4331 {
rlm@1 4332 IF |= 0x20;
rlm@1 4333 UPDATE_REG(0x202, IF);
rlm@1 4334 }
rlm@1 4335 }
rlm@1 4336 UPDATE_REG(0x108, TM2D);
rlm@1 4337 }
rlm@1 4338 }
rlm@1 4339 }
rlm@1 4340 }
rlm@1 4341
rlm@1 4342 if (timer3On)
rlm@1 4343 {
rlm@1 4344 if (TM3CNT & 4)
rlm@1 4345 {
rlm@1 4346 if (timerOverflow & 4)
rlm@1 4347 {
rlm@1 4348 TM3D++;
rlm@1 4349 if (TM3D == 0)
rlm@1 4350 {
rlm@1 4351 TM3D += timer3Reload;
rlm@1 4352 if (TM3CNT & 0x40)
rlm@1 4353 {
rlm@1 4354 IF |= 0x40;
rlm@1 4355 UPDATE_REG(0x202, IF);
rlm@1 4356 }
rlm@1 4357 }
rlm@1 4358 UPDATE_REG(0x10c, TM3D);
rlm@1 4359 }
rlm@1 4360 }
rlm@1 4361 else
rlm@1 4362 {
rlm@1 4363 if (timer3ClockReload == 1)
rlm@1 4364 {
rlm@1 4365 u32 tm3d = TM3D + clockTicks;
rlm@1 4366 if (tm3d > 0xffff)
rlm@1 4367 {
rlm@1 4368 tm3d += timer3Reload;
rlm@1 4369 if (TM3CNT & 0x40)
rlm@1 4370 {
rlm@1 4371 IF |= 0x40;
rlm@1 4372 UPDATE_REG(0x202, IF);
rlm@1 4373 }
rlm@1 4374 }
rlm@1 4375 TM3D = tm3d & 0xFFFF;
rlm@1 4376 timer3Ticks = 0x10000 - TM3D;
rlm@1 4377 UPDATE_REG(0x10C, TM3D);
rlm@1 4378 }
rlm@1 4379 else
rlm@1 4380 {
rlm@1 4381 timer3Ticks -= clockTicks;
rlm@1 4382 if (timer3Ticks <= 0)
rlm@1 4383 {
rlm@1 4384 timer3Ticks += timer3ClockReload;
rlm@1 4385 TM3D++;
rlm@1 4386
rlm@1 4387 if (TM3D == 0)
rlm@1 4388 {
rlm@1 4389 TM3D = timer3Reload;
rlm@1 4390 if (TM3CNT & 0x40)
rlm@1 4391 {
rlm@1 4392 IF |= 0x40;
rlm@1 4393 UPDATE_REG(0x202, IF);
rlm@1 4394 }
rlm@1 4395 }
rlm@1 4396 UPDATE_REG(0x10C, TM3D);
rlm@1 4397 }
rlm@1 4398 }
rlm@1 4399 }
rlm@1 4400 }
rlm@1 4401 }
rlm@1 4402 // we shouldn't be doing sound in stop state, but we lose synchronization
rlm@1 4403 // if sound is disabled, so in stop state, soundTick will just produce
rlm@1 4404 // mute sound
rlm@1 4405 soundTicks -= clockTicks;
rlm@1 4406 if (soundTicks < 1)
rlm@1 4407 {
rlm@1 4408 soundTick();
rlm@1 4409 soundTicks += SOUND_CLOCK_TICKS;
rlm@1 4410 }
rlm@1 4411 timerOverflow = 0;
rlm@1 4412
rlm@1 4413 #ifdef PROFILING
rlm@1 4414 profilingTicks -= clockTicks;
rlm@1 4415 if (profilingTicks <= 0)
rlm@1 4416 {
rlm@1 4417 profilingTicks += profilingTicksReload;
rlm@1 4418 if (profilBuffer && profilSize)
rlm@1 4419 {
rlm@1 4420 u16 *b = (u16 *)profilBuffer;
rlm@1 4421 int pc = ((reg[15].I - profilLowPC) * profilScale) / 0x10000;
rlm@1 4422 if (pc >= 0 && pc < profilSize)
rlm@1 4423 {
rlm@1 4424 b[pc]++;
rlm@1 4425 }
rlm@1 4426 }
rlm@1 4427 }
rlm@1 4428 #endif
rlm@1 4429
rlm@1 4430 ticks -= clockTicks;
rlm@1 4431 cpuLoopTicks = CPUUpdateTicks();
rlm@1 4432
rlm@1 4433 // FIXME: it is too bad that it is still not determined whether the loop can be exited at this point
rlm@1 4434 if (cpuDmaTicksToUpdate > 0)
rlm@1 4435 {
rlm@1 4436 clockTicks = cpuSavedTicks;
rlm@1 4437 if (clockTicks > cpuDmaTicksToUpdate)
rlm@1 4438 clockTicks = cpuDmaTicksToUpdate;
rlm@1 4439 cpuDmaTicksToUpdate -= clockTicks;
rlm@1 4440 if (cpuDmaTicksToUpdate < 0)
rlm@1 4441 cpuDmaTicksToUpdate = 0;
rlm@1 4442 goto updateLoop; // this is evil
rlm@1 4443 }
rlm@1 4444
rlm@1 4445 if (IF && (IME & 1) && armIrqEnable)
rlm@1 4446 {
rlm@1 4447 int res = IF & IE;
rlm@1 4448 if (stopState)
rlm@1 4449 res &= 0x3080;
rlm@1 4450 if (res)
rlm@1 4451 {
rlm@1 4452 if (intState)
rlm@1 4453 {
rlm@1 4454 CPUInterrupt();
rlm@1 4455 intState = false;
rlm@1 4456 if (holdState)
rlm@1 4457 {
rlm@1 4458 holdState = false;
rlm@1 4459 stopState = false;
rlm@1 4460 }
rlm@1 4461 }
rlm@1 4462 else
rlm@1 4463 {
rlm@1 4464 if (!holdState)
rlm@1 4465 {
rlm@1 4466 intState = true;
rlm@1 4467 cpuLoopTicks = 5;
rlm@1 4468 cpuSavedTicks = 5;
rlm@1 4469 }
rlm@1 4470 else
rlm@1 4471 {
rlm@1 4472 CPUInterrupt();
rlm@1 4473 if (holdState)
rlm@1 4474 {
rlm@1 4475 holdState = false;
rlm@1 4476 stopState = false;
rlm@1 4477 }
rlm@1 4478 }
rlm@1 4479 }
rlm@1 4480 }
rlm@1 4481 }
rlm@1 4482
rlm@1 4483 if (useOldFrameTiming)
rlm@1 4484 {
rlm@1 4485 if (ticks <= 0)
rlm@1 4486 {
rlm@1 4487 newFrame = true;
rlm@1 4488 break;
rlm@1 4489 }
rlm@1 4490 }
rlm@1 4491 else if (newFrame)
rlm@1 4492 {
rlm@1 4493 // FIXME: it should be enough to use frameBoundary only if there were no need for supporting the old timing
rlm@1 4494 // but is there still any GBA .vbm that uses the old timing?
rlm@1 4495 /// extern void VBAOnEnteringFrameBoundary();
rlm@1 4496 /// VBAOnEnteringFrameBoundary();
rlm@1 4497
rlm@1 4498 break;
rlm@1 4499 }
rlm@1 4500 }
rlm@1 4501 }
rlm@1 4502 }
rlm@1 4503
rlm@1 4504 struct EmulatedSystem GBASystem =
rlm@1 4505 {
rlm@1 4506 // emuMain
rlm@1 4507 CPULoop,
rlm@1 4508 // emuReset
rlm@1 4509 CPUReset,
rlm@1 4510 // emuCleanUp
rlm@1 4511 CPUCleanUp,
rlm@1 4512 // emuReadBattery
rlm@1 4513 CPUReadBatteryFile,
rlm@1 4514 // emuWriteBattery
rlm@1 4515 CPUWriteBatteryFile,
rlm@1 4516 // emuReadBatteryFromStream
rlm@1 4517 CPUReadBatteryFromStream,
rlm@1 4518 // emuWriteBatteryToStream
rlm@1 4519 CPUWriteBatteryToStream,
rlm@1 4520 // emuReadState
rlm@1 4521 CPUReadState,
rlm@1 4522 // emuWriteState
rlm@1 4523 CPUWriteState,
rlm@1 4524 // emuReadStateFromStream
rlm@1 4525 CPUReadStateFromStream,
rlm@1 4526 // emuWriteStateToStream
rlm@1 4527 CPUWriteStateToStream,
rlm@1 4528 // emuReadMemState
rlm@1 4529 CPUReadMemState,
rlm@1 4530 // emuWriteMemState
rlm@1 4531 CPUWriteMemState,
rlm@1 4532 // emuWritePNG
rlm@1 4533 CPUWritePNGFile,
rlm@1 4534 // emuWriteBMP
rlm@1 4535 CPUWriteBMPFile,
rlm@1 4536 // emuUpdateCPSR
rlm@1 4537 CPUUpdateCPSR,
rlm@1 4538 // emuHasDebugger
rlm@1 4539 true,
rlm@1 4540 // emuCount
rlm@1 4541 #ifdef FINAL_VERSION
rlm@1 4542 250000,
rlm@1 4543 #else
rlm@1 4544 5000,
rlm@1 4545 #endif
rlm@1 4546 };
rlm@1 4547
rlm@1 4548 // is there a reason to use more than one set of counters?
rlm@1 4549 EmulatedSystemCounters &GBASystemCounters = systemCounters;
rlm@1 4550
rlm@1 4551 /*
rlm@1 4552 EmulatedSystemCounters GBASystemCounters =
rlm@1 4553 {
rlm@1 4554 // frameCount
rlm@1 4555 0,
rlm@1 4556 // lagCount
rlm@1 4557 0,
rlm@1 4558 // lagged
rlm@1 4559 true,
rlm@1 4560 // laggedLast
rlm@1 4561 true,
rlm@1 4562 };
rlm@1 4563 */
rlm@1 4564
rlm@1 4565
rlm@1 4566 #undef CPU_BREAK_LOOP
rlm@1 4567 #undef CPU_BREAK_LOOP2