Mercurial > vba-clojure
diff src/gba/GBA.cpp @ 19:5e8e5083da94
brought in common and gba, fixed problems with outdated Makefile.am files in both of these packages
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 04 Mar 2012 14:33:52 -0600 |
parents | f9f4f1b99eed |
children | 1ff2c546f5ad |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/gba/GBA.cpp Sun Mar 04 14:33:52 2012 -0600 1.3 @@ -0,0 +1,4567 @@ 1.4 +#include <cstdio> 1.5 +#include <cstdlib> 1.6 +#include <cstdarg> 1.7 +#include <cstring> 1.8 + 1.9 +#include "../Port.h" 1.10 +#include "../NLS.h" 1.11 +#include "GBA.h" 1.12 +//#include "GBAGlobals.h" 1.13 +#include "GBACheats.h" // FIXME: SDL requires this included before "GBAinline.h" 1.14 +#include "GBAinline.h" 1.15 +#include "GBAGfx.h" 1.16 +#include "GBASound.h" 1.17 +#include "EEprom.h" 1.18 +#include "Flash.h" 1.19 +#include "Sram.h" 1.20 +#include "bios.h" 1.21 +#include "elf.h" 1.22 +#include "agbprint.h" 1.23 +#include "../common/unzip.h" 1.24 +#include "../common/Util.h" 1.25 +#include "../common/movie.h" 1.26 +#include "../common/vbalua.h" 1.27 + 1.28 +#ifdef PROFILING 1.29 +#include "../prof/prof.h" 1.30 +#endif 1.31 + 1.32 +#define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]), value) 1.33 + 1.34 +#ifdef __GNUC__ 1.35 +#define _stricmp strcasecmp 1.36 +#endif 1.37 + 1.38 +#define CPU_BREAK_LOOP \ 1.39 + cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \ 1.40 + *extCpuLoopTicks = *extClockTicks; 1.41 + 1.42 +#define CPU_BREAK_LOOP_2 \ 1.43 + cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \ 1.44 + *extCpuLoopTicks = *extClockTicks; \ 1.45 + *extTicks = *extClockTicks; 1.46 + 1.47 +int32 cpuDmaTicksToUpdate = 0; 1.48 +int32 cpuDmaCount = 0; 1.49 +bool8 cpuDmaHack = 0; 1.50 +u32 cpuDmaLast = 0; 1.51 +int32 dummyAddress = 0; 1.52 + 1.53 +int32 *extCpuLoopTicks = NULL; 1.54 +int32 *extClockTicks = NULL; 1.55 +int32 *extTicks = NULL; 1.56 + 1.57 +#if (defined(WIN32) && !defined(SDL)) 1.58 +HANDLE mapROM; // shared memory handles 1.59 +HANDLE mapWORKRAM; 1.60 +HANDLE mapBIOS; 1.61 +HANDLE mapIRAM; 1.62 +HANDLE mapPALETTERAM; 1.63 +HANDLE mapVRAM; 1.64 +HANDLE mapOAM; 1.65 +HANDLE mapPIX; 1.66 +HANDLE mapIOMEM; 1.67 +#endif 1.68 + 1.69 +int32 gbaSaveType = 0; // used to remember the save type on reset 1.70 +bool8 intState = false; 1.71 +bool8 stopState = false; 1.72 +bool8 holdState = false; 1.73 +int32 holdType = 0; 1.74 +bool8 cpuSramEnabled = true; 1.75 +bool8 cpuFlashEnabled = true; 1.76 +bool8 cpuEEPROMEnabled = true; 1.77 +bool8 cpuEEPROMSensorEnabled = false; 1.78 + 1.79 +#ifdef PROFILING 1.80 +int profilingTicks = 0; 1.81 +int profilingTicksReload = 0; 1.82 +static char *profilBuffer = NULL; 1.83 +static int profilSize = 0; 1.84 +static u32 profilLowPC = 0; 1.85 +static int profilScale = 0; 1.86 +#endif 1.87 +bool8 freezeWorkRAM[0x40000]; 1.88 +bool8 freezeInternalRAM[0x8000]; 1.89 +int32 lcdTicks = 960; 1.90 +bool8 timer0On = false; 1.91 +int32 timer0Ticks = 0; 1.92 +int32 timer0Reload = 0; 1.93 +int32 timer0ClockReload = 0; 1.94 +bool8 timer1On = false; 1.95 +int32 timer1Ticks = 0; 1.96 +int32 timer1Reload = 0; 1.97 +int32 timer1ClockReload = 0; 1.98 +bool8 timer2On = false; 1.99 +int32 timer2Ticks = 0; 1.100 +int32 timer2Reload = 0; 1.101 +int32 timer2ClockReload = 0; 1.102 +bool8 timer3On = false; 1.103 +int32 timer3Ticks = 0; 1.104 +int32 timer3Reload = 0; 1.105 +int32 timer3ClockReload = 0; 1.106 +u32 dma0Source = 0; 1.107 +u32 dma0Dest = 0; 1.108 +u32 dma1Source = 0; 1.109 +u32 dma1Dest = 0; 1.110 +u32 dma2Source = 0; 1.111 +u32 dma2Dest = 0; 1.112 +u32 dma3Source = 0; 1.113 +u32 dma3Dest = 0; 1.114 +void (*cpuSaveGameFunc)(u32, u8) = flashSaveDecide; 1.115 +void (*renderLine)() = mode0RenderLine; 1.116 +bool8 fxOn = false; 1.117 +bool8 windowOn = false; 1.118 +int32 frameSkipCount = 0; 1.119 +u32 gbaLastTime = 0; 1.120 +int32 gbaFrameCount = 0; 1.121 +bool8 prefetchActive = false, prefetchPrevActive = false, prefetchApplies = false; 1.122 +char buffer[1024]; 1.123 +FILE *out = NULL; 1.124 + 1.125 +static bool newFrame = true; 1.126 +static bool pauseAfterFrameAdvance = false; 1.127 + 1.128 +const int32 TIMER_TICKS[4] = { 1.129 + 1, 1.130 + 64, 1.131 + 256, 1.132 + 1024 1.133 +}; 1.134 + 1.135 +const int32 thumbCycles[] = { 1.136 +// 0 1 2 3 4 5 6 7 8 9 a b c d e f 1.137 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1.138 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1.139 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1.140 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1.141 + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4 1.142 + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5 1.143 + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6 1.144 + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7 1.145 + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8 1.146 + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9 1.147 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a 1.148 + 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b 1.149 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c 1.150 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d 1.151 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e 1.152 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f 1.153 +}; 1.154 + 1.155 +const int32 gamepakRamWaitState[4] = { 4, 3, 2, 8 }; 1.156 +const int32 gamepakWaitState[8] = { 4, 3, 2, 8, 4, 3, 2, 8 }; 1.157 +const int32 gamepakWaitState0[8] = { 2, 2, 2, 2, 1, 1, 1, 1 }; 1.158 +const int32 gamepakWaitState1[8] = { 4, 4, 4, 4, 1, 1, 1, 1 }; 1.159 +const int32 gamepakWaitState2[8] = { 8, 8, 8, 8, 1, 1, 1, 1 }; 1.160 + 1.161 +int32 memoryWait[16] = 1.162 +{ 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; 1.163 +int32 memoryWait32[16] = 1.164 +{ 0, 0, 9, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0 }; 1.165 +int32 memoryWaitSeq[16] = 1.166 +{ 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 }; 1.167 +int32 memoryWaitSeq32[16] = 1.168 +{ 2, 0, 3, 0, 0, 2, 2, 0, 4, 4, 8, 8, 16, 16, 8, 0 }; 1.169 +int32 memoryWaitFetch[16] = 1.170 +{ 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; 1.171 +int32 memoryWaitFetch32[16] = 1.172 +{ 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 }; 1.173 + 1.174 +const int32 cpuMemoryWait[16] = { 1.175 + 0, 0, 2, 0, 0, 0, 0, 0, 1.176 + 2, 2, 2, 2, 2, 2, 0, 0 1.177 +}; 1.178 +const int32 cpuMemoryWait32[16] = { 1.179 + 0, 0, 3, 0, 0, 0, 0, 0, 1.180 + 3, 3, 3, 3, 3, 3, 0, 0 1.181 +}; 1.182 + 1.183 +const bool8 memory32[16] = { 1.184 + true, false, false, true, true, false, false, true, false, false, false, false, false, false, true, false 1.185 +}; 1.186 + 1.187 +u8 biosProtected[4]; 1.188 + 1.189 +u8 cpuBitsSet[256]; 1.190 +u8 cpuLowestBitSet[256]; 1.191 + 1.192 +#ifdef WORDS_BIGENDIAN 1.193 +bool8 cpuBiosSwapped = false; 1.194 +#endif 1.195 + 1.196 +u32 myROM[] = { 1.197 + 0xEA000006, 1.198 + 0xEA000093, 1.199 + 0xEA000006, 1.200 + 0x00000000, 1.201 + 0x00000000, 1.202 + 0x00000000, 1.203 + 0xEA000088, 1.204 + 0x00000000, 1.205 + 0xE3A00302, 1.206 + 0xE1A0F000, 1.207 + 0xE92D5800, 1.208 + 0xE55EC002, 1.209 + 0xE28FB03C, 1.210 + 0xE79BC10C, 1.211 + 0xE14FB000, 1.212 + 0xE92D0800, 1.213 + 0xE20BB080, 1.214 + 0xE38BB01F, 1.215 + 0xE129F00B, 1.216 + 0xE92D4004, 1.217 + 0xE1A0E00F, 1.218 + 0xE12FFF1C, 1.219 + 0xE8BD4004, 1.220 + 0xE3A0C0D3, 1.221 + 0xE129F00C, 1.222 + 0xE8BD0800, 1.223 + 0xE169F00B, 1.224 + 0xE8BD5800, 1.225 + 0xE1B0F00E, 1.226 + 0x0000009C, 1.227 + 0x0000009C, 1.228 + 0x0000009C, 1.229 + 0x0000009C, 1.230 + 0x000001F8, 1.231 + 0x000001F0, 1.232 + 0x000000AC, 1.233 + 0x000000A0, 1.234 + 0x000000FC, 1.235 + 0x00000168, 1.236 + 0xE12FFF1E, 1.237 + 0xE1A03000, 1.238 + 0xE1A00001, 1.239 + 0xE1A01003, 1.240 + 0xE2113102, 1.241 + 0x42611000, 1.242 + 0xE033C040, 1.243 + 0x22600000, 1.244 + 0xE1B02001, 1.245 + 0xE15200A0, 1.246 + 0x91A02082, 1.247 + 0x3AFFFFFC, 1.248 + 0xE1500002, 1.249 + 0xE0A33003, 1.250 + 0x20400002, 1.251 + 0xE1320001, 1.252 + 0x11A020A2, 1.253 + 0x1AFFFFF9, 1.254 + 0xE1A01000, 1.255 + 0xE1A00003, 1.256 + 0xE1B0C08C, 1.257 + 0x22600000, 1.258 + 0x42611000, 1.259 + 0xE12FFF1E, 1.260 + 0xE92D0010, 1.261 + 0xE1A0C000, 1.262 + 0xE3A01001, 1.263 + 0xE1500001, 1.264 + 0x81A000A0, 1.265 + 0x81A01081, 1.266 + 0x8AFFFFFB, 1.267 + 0xE1A0000C, 1.268 + 0xE1A04001, 1.269 + 0xE3A03000, 1.270 + 0xE1A02001, 1.271 + 0xE15200A0, 1.272 + 0x91A02082, 1.273 + 0x3AFFFFFC, 1.274 + 0xE1500002, 1.275 + 0xE0A33003, 1.276 + 0x20400002, 1.277 + 0xE1320001, 1.278 + 0x11A020A2, 1.279 + 0x1AFFFFF9, 1.280 + 0xE0811003, 1.281 + 0xE1B010A1, 1.282 + 0xE1510004, 1.283 + 0x3AFFFFEE, 1.284 + 0xE1A00004, 1.285 + 0xE8BD0010, 1.286 + 0xE12FFF1E, 1.287 + 0xE0010090, 1.288 + 0xE1A01741, 1.289 + 0xE2611000, 1.290 + 0xE3A030A9, 1.291 + 0xE0030391, 1.292 + 0xE1A03743, 1.293 + 0xE2833E39, 1.294 + 0xE0030391, 1.295 + 0xE1A03743, 1.296 + 0xE2833C09, 1.297 + 0xE283301C, 1.298 + 0xE0030391, 1.299 + 0xE1A03743, 1.300 + 0xE2833C0F, 1.301 + 0xE28330B6, 1.302 + 0xE0030391, 1.303 + 0xE1A03743, 1.304 + 0xE2833C16, 1.305 + 0xE28330AA, 1.306 + 0xE0030391, 1.307 + 0xE1A03743, 1.308 + 0xE2833A02, 1.309 + 0xE2833081, 1.310 + 0xE0030391, 1.311 + 0xE1A03743, 1.312 + 0xE2833C36, 1.313 + 0xE2833051, 1.314 + 0xE0030391, 1.315 + 0xE1A03743, 1.316 + 0xE2833CA2, 1.317 + 0xE28330F9, 1.318 + 0xE0000093, 1.319 + 0xE1A00840, 1.320 + 0xE12FFF1E, 1.321 + 0xE3A00001, 1.322 + 0xE3A01001, 1.323 + 0xE92D4010, 1.324 + 0xE3A0C301, 1.325 + 0xE3A03000, 1.326 + 0xE3A04001, 1.327 + 0xE3500000, 1.328 + 0x1B000004, 1.329 + 0xE5CC3301, 1.330 + 0xEB000002, 1.331 + 0x0AFFFFFC, 1.332 + 0xE8BD4010, 1.333 + 0xE12FFF1E, 1.334 + 0xE5CC3208, 1.335 + 0xE15C20B8, 1.336 + 0xE0110002, 1.337 + 0x10200002, 1.338 + 0x114C00B8, 1.339 + 0xE5CC4208, 1.340 + 0xE12FFF1E, 1.341 + 0xE92D500F, 1.342 + 0xE3A00301, 1.343 + 0xE1A0E00F, 1.344 + 0xE510F004, 1.345 + 0xE8BD500F, 1.346 + 0xE25EF004, 1.347 + 0xE59FD044, 1.348 + 0xE92D5000, 1.349 + 0xE14FC000, 1.350 + 0xE10FE000, 1.351 + 0xE92D5000, 1.352 + 0xE3A0C302, 1.353 + 0xE5DCE09C, 1.354 + 0xE35E00A5, 1.355 + 0x1A000004, 1.356 + 0x05DCE0B4, 1.357 + 0x021EE080, 1.358 + 0xE28FE004, 1.359 + 0x159FF018, 1.360 + 0x059FF018, 1.361 + 0xE59FD018, 1.362 + 0xE8BD5000, 1.363 + 0xE169F00C, 1.364 + 0xE8BD5000, 1.365 + 0xE25EF004, 1.366 + 0x03007FF0, 1.367 + 0x09FE2000, 1.368 + 0x09FFC000, 1.369 + 0x03007FE0 1.370 +}; 1.371 + 1.372 +variable_desc saveGameStruct[] = { 1.373 + { &DISPCNT, sizeof(u16) }, 1.374 + { &DISPSTAT, sizeof(u16) }, 1.375 + { &VCOUNT, sizeof(u16) }, 1.376 + { &BG0CNT, sizeof(u16) }, 1.377 + { &BG1CNT, sizeof(u16) }, 1.378 + { &BG2CNT, sizeof(u16) }, 1.379 + { &BG3CNT, sizeof(u16) }, 1.380 + { &BG0HOFS, sizeof(u16) }, 1.381 + { &BG0VOFS, sizeof(u16) }, 1.382 + { &BG1HOFS, sizeof(u16) }, 1.383 + { &BG1VOFS, sizeof(u16) }, 1.384 + { &BG2HOFS, sizeof(u16) }, 1.385 + { &BG2VOFS, sizeof(u16) }, 1.386 + { &BG3HOFS, sizeof(u16) }, 1.387 + { &BG3VOFS, sizeof(u16) }, 1.388 + { &BG2PA, sizeof(u16) }, 1.389 + { &BG2PB, sizeof(u16) }, 1.390 + { &BG2PC, sizeof(u16) }, 1.391 + { &BG2PD, sizeof(u16) }, 1.392 + { &BG2X_L, sizeof(u16) }, 1.393 + { &BG2X_H, sizeof(u16) }, 1.394 + { &BG2Y_L, sizeof(u16) }, 1.395 + { &BG2Y_H, sizeof(u16) }, 1.396 + { &BG3PA, sizeof(u16) }, 1.397 + { &BG3PB, sizeof(u16) }, 1.398 + { &BG3PC, sizeof(u16) }, 1.399 + { &BG3PD, sizeof(u16) }, 1.400 + { &BG3X_L, sizeof(u16) }, 1.401 + { &BG3X_H, sizeof(u16) }, 1.402 + { &BG3Y_L, sizeof(u16) }, 1.403 + { &BG3Y_H, sizeof(u16) }, 1.404 + { &WIN0H, sizeof(u16) }, 1.405 + { &WIN1H, sizeof(u16) }, 1.406 + { &WIN0V, sizeof(u16) }, 1.407 + { &WIN1V, sizeof(u16) }, 1.408 + { &WININ, sizeof(u16) }, 1.409 + { &WINOUT, sizeof(u16) }, 1.410 + { &MOSAIC, sizeof(u16) }, 1.411 + { &BLDMOD, sizeof(u16) }, 1.412 + { &COLEV, sizeof(u16) }, 1.413 + { &COLY, sizeof(u16) }, 1.414 + { &DM0SAD_L, sizeof(u16) }, 1.415 + { &DM0SAD_H, sizeof(u16) }, 1.416 + { &DM0DAD_L, sizeof(u16) }, 1.417 + { &DM0DAD_H, sizeof(u16) }, 1.418 + { &DM0CNT_L, sizeof(u16) }, 1.419 + { &DM0CNT_H, sizeof(u16) }, 1.420 + { &DM1SAD_L, sizeof(u16) }, 1.421 + { &DM1SAD_H, sizeof(u16) }, 1.422 + { &DM1DAD_L, sizeof(u16) }, 1.423 + { &DM1DAD_H, sizeof(u16) }, 1.424 + { &DM1CNT_L, sizeof(u16) }, 1.425 + { &DM1CNT_H, sizeof(u16) }, 1.426 + { &DM2SAD_L, sizeof(u16) }, 1.427 + { &DM2SAD_H, sizeof(u16) }, 1.428 + { &DM2DAD_L, sizeof(u16) }, 1.429 + { &DM2DAD_H, sizeof(u16) }, 1.430 + { &DM2CNT_L, sizeof(u16) }, 1.431 + { &DM2CNT_H, sizeof(u16) }, 1.432 + { &DM3SAD_L, sizeof(u16) }, 1.433 + { &DM3SAD_H, sizeof(u16) }, 1.434 + { &DM3DAD_L, sizeof(u16) }, 1.435 + { &DM3DAD_H, sizeof(u16) }, 1.436 + { &DM3CNT_L, sizeof(u16) }, 1.437 + { &DM3CNT_H, sizeof(u16) }, 1.438 + { &TM0D, sizeof(u16) }, 1.439 + { &TM0CNT, sizeof(u16) }, 1.440 + { &TM1D, sizeof(u16) }, 1.441 + { &TM1CNT, sizeof(u16) }, 1.442 + { &TM2D, sizeof(u16) }, 1.443 + { &TM2CNT, sizeof(u16) }, 1.444 + { &TM3D, sizeof(u16) }, 1.445 + { &TM3CNT, sizeof(u16) }, 1.446 + { &P1, sizeof(u16) }, 1.447 + { &IE, sizeof(u16) }, 1.448 + { &IF, sizeof(u16) }, 1.449 + { &IME, sizeof(u16) }, 1.450 + { &holdState, sizeof(bool8) }, 1.451 + { &holdType, sizeof(int32) }, 1.452 + { &lcdTicks, sizeof(int32) }, 1.453 + { &timer0On, sizeof(bool8) }, 1.454 + { &timer0Ticks, sizeof(int32) }, 1.455 + { &timer0Reload, sizeof(int32) }, 1.456 + { &timer0ClockReload, sizeof(int32) }, 1.457 + { &timer1On, sizeof(bool8) }, 1.458 + { &timer1Ticks, sizeof(int32) }, 1.459 + { &timer1Reload, sizeof(int32) }, 1.460 + { &timer1ClockReload, sizeof(int32) }, 1.461 + { &timer2On, sizeof(bool8) }, 1.462 + { &timer2Ticks, sizeof(int32) }, 1.463 + { &timer2Reload, sizeof(int32) }, 1.464 + { &timer2ClockReload, sizeof(int32) }, 1.465 + { &timer3On, sizeof(bool8) }, 1.466 + { &timer3Ticks, sizeof(int32) }, 1.467 + { &timer3Reload, sizeof(int32) }, 1.468 + { &timer3ClockReload, sizeof(int32) }, 1.469 + { &dma0Source, sizeof(u32) }, 1.470 + { &dma0Dest, sizeof(u32) }, 1.471 + { &dma1Source, sizeof(u32) }, 1.472 + { &dma1Dest, sizeof(u32) }, 1.473 + { &dma2Source, sizeof(u32) }, 1.474 + { &dma2Dest, sizeof(u32) }, 1.475 + { &dma3Source, sizeof(u32) }, 1.476 + { &dma3Dest, sizeof(u32) }, 1.477 + { &fxOn, sizeof(bool8) }, 1.478 + { &windowOn, sizeof(bool8) }, 1.479 + { &N_FLAG, sizeof(bool8) }, 1.480 + { &C_FLAG, sizeof(bool8) }, 1.481 + { &Z_FLAG, sizeof(bool8) }, 1.482 + { &V_FLAG, sizeof(bool8) }, 1.483 + { &armState, sizeof(bool8) }, 1.484 + { &armIrqEnable, sizeof(bool8) }, 1.485 + { &armNextPC, sizeof(u32) }, 1.486 + { &armMode, sizeof(int32) }, 1.487 + { &saveType, sizeof(int32) }, 1.488 + { NULL, 0 } 1.489 +}; 1.490 + 1.491 +//int cpuLoopTicks = 0; 1.492 +int cpuSavedTicks = 0; 1.493 + 1.494 +#ifdef PROFILING 1.495 +void cpuProfil(char *buf, int size, u32 lowPC, int scale) 1.496 +{ 1.497 + profilBuffer = buf; 1.498 + profilSize = size; 1.499 + profilLowPC = lowPC; 1.500 + profilScale = scale; 1.501 +} 1.502 + 1.503 +void cpuEnableProfiling(int hz) 1.504 +{ 1.505 + if (hz == 0) 1.506 + hz = 100; 1.507 + profilingTicks = profilingTicksReload = 16777216 / hz; 1.508 + profSetHertz(hz); 1.509 +} 1.510 + 1.511 +#endif 1.512 + 1.513 +inline int CPUUpdateTicksAccess32(u32 address) 1.514 +{ 1.515 + return memoryWait32[(address >> 24) & 15]; 1.516 +} 1.517 + 1.518 +inline int CPUUpdateTicksAccess16(u32 address) 1.519 +{ 1.520 + return memoryWait[(address >> 24) & 15]; 1.521 +} 1.522 + 1.523 +inline int CPUUpdateTicksAccessSeq32(u32 address) 1.524 +{ 1.525 + return memoryWaitSeq32[(address >> 24) & 15]; 1.526 +} 1.527 + 1.528 +inline int CPUUpdateTicksAccessSeq16(u32 address) 1.529 +{ 1.530 + return memoryWaitSeq[(address >> 24) & 15]; 1.531 +} 1.532 + 1.533 +inline int CPUUpdateTicks() 1.534 +{ 1.535 + int cpuLoopTicks = lcdTicks; 1.536 + 1.537 + if (soundTicks < cpuLoopTicks) 1.538 + cpuLoopTicks = soundTicks; 1.539 + 1.540 + if (timer0On && !(TM0CNT & 4) && (timer0Ticks < cpuLoopTicks)) 1.541 + { 1.542 + cpuLoopTicks = timer0Ticks; 1.543 + } 1.544 + if (timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks)) 1.545 + { 1.546 + cpuLoopTicks = timer1Ticks; 1.547 + } 1.548 + if (timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks)) 1.549 + { 1.550 + cpuLoopTicks = timer2Ticks; 1.551 + } 1.552 + if (timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks)) 1.553 + { 1.554 + cpuLoopTicks = timer3Ticks; 1.555 + } 1.556 +#ifdef PROFILING 1.557 + if (profilingTicksReload != 0) 1.558 + { 1.559 + if (profilingTicks < cpuLoopTicks) 1.560 + { 1.561 + cpuLoopTicks = profilingTicks; 1.562 + } 1.563 + } 1.564 +#endif 1.565 + cpuSavedTicks = cpuLoopTicks; 1.566 + return cpuLoopTicks; 1.567 +} 1.568 + 1.569 +void CPUUpdateWindow0() 1.570 +{ 1.571 + int x00 = WIN0H >> 8; 1.572 + int x01 = WIN0H & 255; 1.573 + 1.574 + if (x00 <= x01) 1.575 + { 1.576 + for (int i = 0; i < 240; i++) 1.577 + { 1.578 + gfxInWin0[i] = (i >= x00 && i < x01); 1.579 + } 1.580 + } 1.581 + else 1.582 + { 1.583 + for (int i = 0; i < 240; i++) 1.584 + { 1.585 + gfxInWin0[i] = (i >= x00 || i < x01); 1.586 + } 1.587 + } 1.588 +} 1.589 + 1.590 +void CPUUpdateWindow1() 1.591 +{ 1.592 + int x00 = WIN1H >> 8; 1.593 + int x01 = WIN1H & 255; 1.594 + 1.595 + if (x00 <= x01) 1.596 + { 1.597 + for (int i = 0; i < 240; i++) 1.598 + { 1.599 + gfxInWin1[i] = (i >= x00 && i < x01); 1.600 + } 1.601 + } 1.602 + else 1.603 + { 1.604 + for (int i = 0; i < 240; i++) 1.605 + { 1.606 + gfxInWin1[i] = (i >= x00 || i < x01); 1.607 + } 1.608 + } 1.609 +} 1.610 + 1.611 +#define CLEAR_ARRAY(a) \ 1.612 + { \ 1.613 + u32 *array = (a); \ 1.614 + for (int i = 0; i < 240; i++) { \ 1.615 + *array++ = 0x80000000; \ 1.616 + } \ 1.617 + } \ 1.618 + 1.619 +void CPUUpdateRenderBuffers(bool force) 1.620 +{ 1.621 + if (!(layerEnable & 0x0100) || force) 1.622 + { 1.623 + CLEAR_ARRAY(line0); 1.624 + } 1.625 + if (!(layerEnable & 0x0200) || force) 1.626 + { 1.627 + CLEAR_ARRAY(line1); 1.628 + } 1.629 + if (!(layerEnable & 0x0400) || force) 1.630 + { 1.631 + CLEAR_ARRAY(line2); 1.632 + } 1.633 + if (!(layerEnable & 0x0800) || force) 1.634 + { 1.635 + CLEAR_ARRAY(line3); 1.636 + } 1.637 +} 1.638 + 1.639 +bool CPUWriteStateToStream(gzFile gzFile) 1.640 +{ 1.641 + utilWriteInt(gzFile, SAVE_GAME_VERSION); 1.642 + 1.643 + utilGzWrite(gzFile, &rom[0xa0], 16); 1.644 + 1.645 + utilWriteInt(gzFile, useBios); 1.646 + 1.647 + utilGzWrite(gzFile, ®[0], sizeof(reg)); 1.648 + 1.649 + utilWriteData(gzFile, saveGameStruct); 1.650 + 1.651 + // new to version 0.7.1 1.652 + utilWriteInt(gzFile, stopState); 1.653 + // new to version 0.8 1.654 + utilWriteInt(gzFile, intState); 1.655 + 1.656 + utilGzWrite(gzFile, internalRAM, 0x8000); 1.657 + utilGzWrite(gzFile, paletteRAM, 0x400); 1.658 + utilGzWrite(gzFile, workRAM, 0x40000); 1.659 + utilGzWrite(gzFile, vram, 0x20000); 1.660 + utilGzWrite(gzFile, oam, 0x400); 1.661 + utilGzWrite(gzFile, pix, 4 * 241 * 162); 1.662 + utilGzWrite(gzFile, ioMem, 0x400); 1.663 + 1.664 + eepromSaveGame(gzFile); 1.665 + flashSaveGame(gzFile); 1.666 + soundSaveGame(gzFile); 1.667 + 1.668 + cheatsSaveGame(gzFile); 1.669 + 1.670 + // version 1.5 1.671 + rtcSaveGame(gzFile); 1.672 + 1.673 + // SAVE_GAME_VERSION_9 (new to re-recording version which is based on 1.72) 1.674 + { 1.675 + extern int32 sensorX, sensorY; // from SDL.cpp 1.676 + utilGzWrite(gzFile, &sensorX, sizeof(sensorX)); 1.677 + utilGzWrite(gzFile, &sensorY, sizeof(sensorY)); 1.678 + bool8 movieActive = VBAMovieActive(); 1.679 + utilGzWrite(gzFile, &movieActive, sizeof(movieActive)); 1.680 + if (movieActive) 1.681 + { 1.682 + uint8 *movie_freeze_buf = NULL; 1.683 + uint32 movie_freeze_size = 0; 1.684 + 1.685 + VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size); 1.686 + if (movie_freeze_buf) 1.687 + { 1.688 + utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size)); 1.689 + utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size); 1.690 + delete [] movie_freeze_buf; 1.691 + } 1.692 + else 1.693 + { 1.694 + systemMessage(0, N_("Failed to save movie snapshot.")); 1.695 + return false; 1.696 + } 1.697 + } 1.698 + utilGzWrite(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount)); 1.699 + } 1.700 + 1.701 + // SAVE_GAME_VERSION_10 1.702 + { 1.703 + utilGzWrite(gzFile, memoryWait, 16 * sizeof(int32)); 1.704 + utilGzWrite(gzFile, memoryWait32, 16 * sizeof(int32)); 1.705 + utilGzWrite(gzFile, memoryWaitSeq, 16 * sizeof(int32)); 1.706 + utilGzWrite(gzFile, memoryWaitSeq32, 16 * sizeof(int32)); 1.707 + utilGzWrite(gzFile, memoryWaitFetch, 16 * sizeof(int32)); 1.708 + utilGzWrite(gzFile, memoryWaitFetch32, 16 * sizeof(int32)); 1.709 + } 1.710 + 1.711 + // SAVE_GAME_VERSION_11 1.712 + { 1.713 + utilGzWrite(gzFile, &prefetchActive, sizeof(bool8)); 1.714 + utilGzWrite(gzFile, &prefetchPrevActive, sizeof(bool8)); 1.715 + utilGzWrite(gzFile, &prefetchApplies, sizeof(bool8)); 1.716 + } 1.717 + 1.718 + // SAVE_GAME_VERSION_12 1.719 + { 1.720 + utilGzWrite(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary 1.721 + utilGzWrite(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used... 1.722 + } 1.723 + 1.724 + // SAVE_GAME_VERSION_13 1.725 + { 1.726 + utilGzWrite(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount)); 1.727 + utilGzWrite(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged)); 1.728 + utilGzWrite(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast)); 1.729 + } 1.730 + 1.731 + return true; 1.732 +} 1.733 + 1.734 +bool CPUWriteState(const char *file) 1.735 +{ 1.736 + gzFile gzFile = utilGzOpen(file, "wb"); 1.737 + 1.738 + if (gzFile == NULL) 1.739 + { 1.740 + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file); 1.741 + return false; 1.742 + } 1.743 + 1.744 + bool res = CPUWriteStateToStream(gzFile); 1.745 + 1.746 + utilGzClose(gzFile); 1.747 + 1.748 + return res; 1.749 +} 1.750 + 1.751 +bool CPUWriteMemState(char *memory, int available) 1.752 +{ 1.753 + gzFile gzFile = utilMemGzOpen(memory, available, "w"); 1.754 + 1.755 + if (gzFile == NULL) 1.756 + { 1.757 + return false; 1.758 + } 1.759 + 1.760 + bool res = CPUWriteStateToStream(gzFile); 1.761 + 1.762 + long pos = utilGzTell(gzFile) + 8; 1.763 + 1.764 + if (pos >= (available)) 1.765 + res = false; 1.766 + 1.767 + utilGzClose(gzFile); 1.768 + 1.769 + return res; 1.770 +} 1.771 + 1.772 +static int tempStateID = 0; 1.773 +static int tempFailCount = 0; 1.774 +static bool backupSafe = true; 1.775 + 1.776 +bool CPUReadStateFromStream(gzFile gzFile) 1.777 +{ 1.778 + bool8 ub; 1.779 + char tempBackupName [128]; 1.780 + if (backupSafe) 1.781 + { 1.782 + sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++); 1.783 + CPUWriteState(tempBackupName); 1.784 + } 1.785 + 1.786 + int version = utilReadInt(gzFile); 1.787 + 1.788 + if (version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1) 1.789 + { 1.790 + systemMessage(MSG_UNSUPPORTED_VBA_SGM, 1.791 + N_("Unsupported VisualBoyAdvance save game version %d"), 1.792 + version); 1.793 + goto failedLoad; 1.794 + } 1.795 + 1.796 + u8 romname[17]; 1.797 + 1.798 + utilGzRead(gzFile, romname, 16); 1.799 + 1.800 + if (memcmp(&rom[0xa0], romname, 16) != 0) 1.801 + { 1.802 + romname[16] = 0; 1.803 + for (int i = 0; i < 16; i++) 1.804 + if (romname[i] < 32) 1.805 + romname[i] = 32; 1.806 + systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname); 1.807 + goto failedLoad; 1.808 + } 1.809 + 1.810 + ub = utilReadInt(gzFile) ? true : false; 1.811 + 1.812 + if (ub != useBios) 1.813 + { 1.814 + if (useBios) 1.815 + systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, 1.816 + N_("Save game is not using the BIOS files")); 1.817 + else 1.818 + systemMessage(MSG_SAVE_GAME_USING_BIOS, 1.819 + N_("Save game is using the BIOS file")); 1.820 + goto failedLoad; 1.821 + } 1.822 + 1.823 + utilGzRead(gzFile, ®[0], sizeof(reg)); 1.824 + 1.825 + utilReadData(gzFile, saveGameStruct); 1.826 + 1.827 + if (version < SAVE_GAME_VERSION_3) 1.828 + stopState = false; 1.829 + else 1.830 + stopState = utilReadInt(gzFile) ? true : false; 1.831 + 1.832 + if (version < SAVE_GAME_VERSION_4) 1.833 + intState = false; 1.834 + else 1.835 + intState = utilReadInt(gzFile) ? true : false; 1.836 + 1.837 + utilGzRead(gzFile, internalRAM, 0x8000); 1.838 + utilGzRead(gzFile, paletteRAM, 0x400); 1.839 + utilGzRead(gzFile, workRAM, 0x40000); 1.840 + utilGzRead(gzFile, vram, 0x20000); 1.841 + utilGzRead(gzFile, oam, 0x400); 1.842 + if (version < SAVE_GAME_VERSION_6) 1.843 + utilGzRead(gzFile, pix, 4 * 240 * 160); 1.844 + else 1.845 + utilGzRead(gzFile, pix, 4 * 241 * 162); 1.846 + utilGzRead(gzFile, ioMem, 0x400); 1.847 + 1.848 + eepromReadGame(gzFile, version); 1.849 + flashReadGame(gzFile, version); 1.850 + soundReadGame(gzFile, version); 1.851 + 1.852 + if (version > SAVE_GAME_VERSION_1) 1.853 + { 1.854 + cheatsReadGame(gzFile); 1.855 + } 1.856 + if (version > SAVE_GAME_VERSION_6) 1.857 + { 1.858 + rtcReadGame(gzFile); 1.859 + } 1.860 + 1.861 + if (version <= SAVE_GAME_VERSION_7) 1.862 + { 1.863 + u32 temp; 1.864 +#define SWAP(a, b, c) \ 1.865 + temp = (a); \ 1.866 + (a) = (b) << 16 | (c); \ 1.867 + (b) = (temp) >> 16; \ 1.868 + (c) = (temp) & 0xFFFF; 1.869 + 1.870 + SWAP(dma0Source, DM0SAD_H, DM0SAD_L); 1.871 + SWAP(dma0Dest, DM0DAD_H, DM0DAD_L); 1.872 + SWAP(dma1Source, DM1SAD_H, DM1SAD_L); 1.873 + SWAP(dma1Dest, DM1DAD_H, DM1DAD_L); 1.874 + SWAP(dma2Source, DM2SAD_H, DM2SAD_L); 1.875 + SWAP(dma2Dest, DM2DAD_H, DM2DAD_L); 1.876 + SWAP(dma3Source, DM3SAD_H, DM3SAD_L); 1.877 + SWAP(dma3Dest, DM3DAD_H, DM3DAD_L); 1.878 + } 1.879 + 1.880 + // set pointers! 1.881 + layerEnable = layerSettings & DISPCNT; 1.882 + 1.883 + CPUUpdateRender(); 1.884 + CPUUpdateRenderBuffers(true); 1.885 + CPUUpdateWindow0(); 1.886 + CPUUpdateWindow1(); 1.887 + gbaSaveType = 0; 1.888 + switch (saveType) 1.889 + { 1.890 + case 0: 1.891 + cpuSaveGameFunc = flashSaveDecide; 1.892 + break; 1.893 + case 1: 1.894 + cpuSaveGameFunc = sramWrite; 1.895 + gbaSaveType = 1; 1.896 + break; 1.897 + case 2: 1.898 + cpuSaveGameFunc = flashWrite; 1.899 + gbaSaveType = 2; 1.900 + break; 1.901 + default: 1.902 + systemMessage(MSG_UNSUPPORTED_SAVE_TYPE, 1.903 + N_("Unsupported save type %d"), saveType); 1.904 + break; 1.905 + } 1.906 + if (eepromInUse) 1.907 + gbaSaveType = 3; 1.908 + 1.909 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 1.910 + 1.911 + if (version >= SAVE_GAME_VERSION_9) // new to re-recording version: 1.912 + { 1.913 + extern int32 sensorX, sensorY; // from SDL.cpp 1.914 + utilGzRead(gzFile, &sensorX, sizeof(sensorX)); 1.915 + utilGzRead(gzFile, &sensorY, sizeof(sensorY)); 1.916 + 1.917 + bool8 movieSnapshot; 1.918 + utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot)); 1.919 + if (VBAMovieActive() && !movieSnapshot) 1.920 + { 1.921 + systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active.")); 1.922 + goto failedLoad; 1.923 + } 1.924 + 1.925 + if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added 1.926 + // later on in the save format 1.927 + { 1.928 + uint32 movieInputDataSize = 0; 1.929 + utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize)); 1.930 + uint8 *local_movie_data = new uint8[movieInputDataSize]; 1.931 + int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize); 1.932 + if (readBytes != movieInputDataSize) 1.933 + { 1.934 + systemMessage(0, N_("Corrupt movie snapshot.")); 1.935 + if (local_movie_data) 1.936 + delete [] local_movie_data; 1.937 + goto failedLoad; 1.938 + } 1.939 + int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize); 1.940 + if (local_movie_data) 1.941 + delete [] local_movie_data; 1.942 + if (code != MOVIE_SUCCESS && VBAMovieActive()) 1.943 + { 1.944 + char errStr [1024]; 1.945 + strcpy(errStr, "Failed to load movie snapshot"); 1.946 + switch (code) 1.947 + { 1.948 + case MOVIE_NOT_FROM_THIS_MOVIE: 1.949 + strcat(errStr, ";\nSnapshot not from this movie"); break; 1.950 + case MOVIE_NOT_FROM_A_MOVIE: 1.951 + strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here... 1.952 + case MOVIE_SNAPSHOT_INCONSISTENT: 1.953 + strcat(errStr, ";\nSnapshot inconsistent with movie"); break; 1.954 + case MOVIE_WRONG_FORMAT: 1.955 + strcat(errStr, ";\nWrong format"); break; 1.956 + } 1.957 + strcat(errStr, "."); 1.958 + systemMessage(0, N_(errStr)); 1.959 + goto failedLoad; 1.960 + } 1.961 + } 1.962 + utilGzRead(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount)); 1.963 + } 1.964 + if (version >= SAVE_GAME_VERSION_10) 1.965 + { 1.966 + utilGzRead(gzFile, memoryWait, 16 * sizeof(int32)); 1.967 + utilGzRead(gzFile, memoryWait32, 16 * sizeof(int32)); 1.968 + utilGzRead(gzFile, memoryWaitSeq, 16 * sizeof(int32)); 1.969 + utilGzRead(gzFile, memoryWaitSeq32, 16 * sizeof(int32)); 1.970 + utilGzRead(gzFile, memoryWaitFetch, 16 * sizeof(int32)); 1.971 + utilGzRead(gzFile, memoryWaitFetch32, 16 * sizeof(int32)); 1.972 + } 1.973 + if (version >= SAVE_GAME_VERSION_11) 1.974 + { 1.975 + utilGzRead(gzFile, &prefetchActive, sizeof(bool8)); 1.976 + //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600); 1.977 + //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600); 1.978 + utilGzRead(gzFile, &prefetchPrevActive, sizeof(bool8)); 1.979 + utilGzRead(gzFile, &prefetchApplies, sizeof(bool8)); 1.980 + } 1.981 + if (version >= SAVE_GAME_VERSION_12) 1.982 + { 1.983 + utilGzRead(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary 1.984 + utilGzRead(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used... 1.985 + } 1.986 + if (version >= SAVE_GAME_VERSION_13) 1.987 + { 1.988 + utilGzRead(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount)); 1.989 + utilGzRead(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged)); 1.990 + utilGzRead(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast)); 1.991 + } 1.992 + 1.993 + if (backupSafe) 1.994 + { 1.995 + remove(tempBackupName); 1.996 + tempFailCount = 0; 1.997 + } 1.998 + systemSetJoypad(0, ~P1 & 0x3FF); 1.999 + VBAUpdateButtonPressDisplay(); 1.1000 + VBAUpdateFrameCountDisplay(); 1.1001 + systemRefreshScreen(); 1.1002 + return true; 1.1003 + 1.1004 +failedLoad: 1.1005 + if (backupSafe) 1.1006 + { 1.1007 + tempFailCount++; 1.1008 + if (tempFailCount < 3) // fail no more than 2 times in a row 1.1009 + CPUReadState(tempBackupName); 1.1010 + remove(tempBackupName); 1.1011 + } 1.1012 + return false; 1.1013 +} 1.1014 + 1.1015 +bool CPUReadMemState(char *memory, int available) 1.1016 +{ 1.1017 + gzFile gzFile = utilMemGzOpen(memory, available, "r"); 1.1018 + 1.1019 + backupSafe = false; 1.1020 + bool res = CPUReadStateFromStream(gzFile); 1.1021 + backupSafe = true; 1.1022 + 1.1023 + utilGzClose(gzFile); 1.1024 + 1.1025 + return res; 1.1026 +} 1.1027 + 1.1028 +bool CPUReadState(const char *file) 1.1029 +{ 1.1030 + gzFile gzFile = utilGzOpen(file, "rb"); 1.1031 + 1.1032 + if (gzFile == NULL) 1.1033 + return false; 1.1034 + 1.1035 + bool res = CPUReadStateFromStream(gzFile); 1.1036 + 1.1037 + utilGzClose(gzFile); 1.1038 + 1.1039 + return res; 1.1040 +} 1.1041 + 1.1042 +bool CPUExportEepromFile(const char *fileName) 1.1043 +{ 1.1044 + if (eepromInUse) 1.1045 + { 1.1046 + FILE *file = fopen(fileName, "wb"); 1.1047 + 1.1048 + if (!file) 1.1049 + { 1.1050 + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), 1.1051 + fileName); 1.1052 + return false; 1.1053 + } 1.1054 + 1.1055 + for (int i = 0; i < eepromSize; ) 1.1056 + { 1.1057 + for (int j = 0; j < 8; j++) 1.1058 + { 1.1059 + if (fwrite(&eepromData[i + 7 - j], 1, 1, file) != 1) 1.1060 + { 1.1061 + fclose(file); 1.1062 + return false; 1.1063 + } 1.1064 + } 1.1065 + i += 8; 1.1066 + } 1.1067 + fclose(file); 1.1068 + } 1.1069 + return true; 1.1070 +} 1.1071 + 1.1072 +bool CPUWriteBatteryToStream(gzFile gzFile) 1.1073 +{ 1.1074 + if (!gzFile) 1.1075 + return false; 1.1076 + 1.1077 + utilWriteInt(gzFile, SAVE_GAME_VERSION); 1.1078 + 1.1079 + // for simplicity, we put both types of battery files should be in the stream, even if one's empty 1.1080 + eepromSaveGame(gzFile); 1.1081 + flashSaveGame(gzFile); 1.1082 + 1.1083 + return true; 1.1084 +} 1.1085 + 1.1086 +bool CPUWriteBatteryFile(const char *fileName) 1.1087 +{ 1.1088 + if (gbaSaveType == 0) 1.1089 + { 1.1090 + if (eepromInUse) 1.1091 + gbaSaveType = 3; 1.1092 + else 1.1093 + switch (saveType) 1.1094 + { 1.1095 + case 1: 1.1096 + gbaSaveType = 1; 1.1097 + break; 1.1098 + case 2: 1.1099 + gbaSaveType = 2; 1.1100 + break; 1.1101 + } 1.1102 + } 1.1103 + 1.1104 + if (gbaSaveType) 1.1105 + { 1.1106 + FILE *file = fopen(fileName, "wb"); 1.1107 + 1.1108 + if (!file) 1.1109 + { 1.1110 + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), 1.1111 + fileName); 1.1112 + return false; 1.1113 + } 1.1114 + 1.1115 + // only save if Flash/Sram in use or EEprom in use 1.1116 + if (gbaSaveType != 3) 1.1117 + { 1.1118 + if (gbaSaveType == 2) 1.1119 + { 1.1120 + if (fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize) 1.1121 + { 1.1122 + fclose(file); 1.1123 + return false; 1.1124 + } 1.1125 + } 1.1126 + else 1.1127 + { 1.1128 + if (fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000) 1.1129 + { 1.1130 + fclose(file); 1.1131 + return false; 1.1132 + } 1.1133 + } 1.1134 + } 1.1135 + else 1.1136 + { 1.1137 + if (fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize) 1.1138 + { 1.1139 + fclose(file); 1.1140 + return false; 1.1141 + } 1.1142 + } 1.1143 + fclose(file); 1.1144 + } 1.1145 + 1.1146 + return true; 1.1147 +} 1.1148 + 1.1149 +bool CPUReadGSASnapshot(const char *fileName) 1.1150 +{ 1.1151 + int i; 1.1152 + FILE *file = fopen(fileName, "rb"); 1.1153 + 1.1154 + if (!file) 1.1155 + { 1.1156 + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); 1.1157 + return false; 1.1158 + } 1.1159 + 1.1160 + // check file size to know what we should read 1.1161 + fseek(file, 0, SEEK_END); 1.1162 + 1.1163 + // long size = ftell(file); 1.1164 + fseek(file, 0x0, SEEK_SET); 1.1165 + fread(&i, 1, 4, file); 1.1166 + fseek(file, i, SEEK_CUR); // Skip SharkPortSave 1.1167 + fseek(file, 4, SEEK_CUR); // skip some sort of flag 1.1168 + fread(&i, 1, 4, file); // name length 1.1169 + fseek(file, i, SEEK_CUR); // skip name 1.1170 + fread(&i, 1, 4, file); // desc length 1.1171 + fseek(file, i, SEEK_CUR); // skip desc 1.1172 + fread(&i, 1, 4, file); // notes length 1.1173 + fseek(file, i, SEEK_CUR); // skip notes 1.1174 + int saveSize; 1.1175 + fread(&saveSize, 1, 4, file); // read length 1.1176 + saveSize -= 0x1c; // remove header size 1.1177 + char buffer[17]; 1.1178 + char buffer2[17]; 1.1179 + fread(buffer, 1, 16, file); 1.1180 + buffer[16] = 0; 1.1181 + for (i = 0; i < 16; i++) 1.1182 + if (buffer[i] < 32) 1.1183 + buffer[i] = 32; 1.1184 + memcpy(buffer2, &rom[0xa0], 16); 1.1185 + buffer2[16] = 0; 1.1186 + for (i = 0; i < 16; i++) 1.1187 + if (buffer2[i] < 32) 1.1188 + buffer2[i] = 32; 1.1189 + if (memcmp(buffer, buffer2, 16)) 1.1190 + { 1.1191 + systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, 1.1192 + N_("Cannot import snapshot for %s. Current game is %s"), 1.1193 + buffer, 1.1194 + buffer2); 1.1195 + fclose(file); 1.1196 + return false; 1.1197 + } 1.1198 + fseek(file, 12, SEEK_CUR); // skip some flags 1.1199 + if (saveSize >= 65536) 1.1200 + { 1.1201 + if (fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize) 1.1202 + { 1.1203 + fclose(file); 1.1204 + return false; 1.1205 + } 1.1206 + } 1.1207 + else 1.1208 + { 1.1209 + systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, 1.1210 + N_("Unsupported snapshot file %s"), 1.1211 + fileName); 1.1212 + fclose(file); 1.1213 + return false; 1.1214 + } 1.1215 + fclose(file); 1.1216 + CPUReset(); 1.1217 + return true; 1.1218 +} 1.1219 + 1.1220 +bool CPUWriteGSASnapshot(const char *fileName, 1.1221 + const char *title, 1.1222 + const char *desc, 1.1223 + const char *notes) 1.1224 +{ 1.1225 + FILE *file = fopen(fileName, "wb"); 1.1226 + 1.1227 + if (!file) 1.1228 + { 1.1229 + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); 1.1230 + return false; 1.1231 + } 1.1232 + 1.1233 + u8 buffer[17]; 1.1234 + 1.1235 + utilPutDword(buffer, 0x0d); // SharkPortSave length 1.1236 + fwrite(buffer, 1, 4, file); 1.1237 + fwrite("SharkPortSave", 1, 0x0d, file); 1.1238 + utilPutDword(buffer, 0x000f0000); 1.1239 + fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save 1.1240 + utilPutDword(buffer, strlen(title)); 1.1241 + fwrite(buffer, 1, 4, file); // title length 1.1242 + fwrite(title, 1, strlen(title), file); 1.1243 + utilPutDword(buffer, strlen(desc)); 1.1244 + fwrite(buffer, 1, 4, file); // desc length 1.1245 + fwrite(desc, 1, strlen(desc), file); 1.1246 + utilPutDword(buffer, strlen(notes)); 1.1247 + fwrite(buffer, 1, 4, file); // notes length 1.1248 + fwrite(notes, 1, strlen(notes), file); 1.1249 + int saveSize = 0x10000; 1.1250 + if (gbaSaveType == 2) 1.1251 + saveSize = flashSize; 1.1252 + int totalSize = saveSize + 0x1c; 1.1253 + 1.1254 + utilPutDword(buffer, totalSize); // length of remainder of save - CRC 1.1255 + fwrite(buffer, 1, 4, file); 1.1256 + 1.1257 + char temp[0x2001c]; 1.1258 + memset(temp, 0, 28); 1.1259 + memcpy(temp, &rom[0xa0], 16); // copy internal name 1.1260 + temp[0x10] = rom[0xbe]; // reserved area (old checksum) 1.1261 + temp[0x11] = rom[0xbf]; // reserved area (old checksum) 1.1262 + temp[0x12] = rom[0xbd]; // complement check 1.1263 + temp[0x13] = rom[0xb0]; // maker 1.1264 + temp[0x14] = 1; // 1 save ? 1.1265 + memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save 1.1266 + fwrite(temp, 1, totalSize, file); // write save + header 1.1267 + u32 crc = 0; 1.1268 + 1.1269 + for (int i = 0; i < totalSize; i++) 1.1270 + { 1.1271 + crc += ((u32)temp[i] << (crc % 0x18)); 1.1272 + } 1.1273 + 1.1274 + utilPutDword(buffer, crc); 1.1275 + fwrite(buffer, 1, 4, file); // CRC? 1.1276 + 1.1277 + fclose(file); 1.1278 + return true; 1.1279 +} 1.1280 + 1.1281 +bool CPUImportEepromFile(const char *fileName) 1.1282 +{ 1.1283 + FILE *file = fopen(fileName, "rb"); 1.1284 + 1.1285 + if (!file) 1.1286 + return false; 1.1287 + 1.1288 + // check file size to know what we should read 1.1289 + fseek(file, 0, SEEK_END); 1.1290 + 1.1291 + long size = ftell(file); 1.1292 + fseek(file, 0, SEEK_SET); 1.1293 + if (size == 512 || size == 0x2000) 1.1294 + { 1.1295 + if (fread(eepromData, 1, size, file) != (size_t)size) 1.1296 + { 1.1297 + fclose(file); 1.1298 + return false; 1.1299 + } 1.1300 + for (int i = 0; i < size; ) 1.1301 + { 1.1302 + u8 tmp = eepromData[i]; 1.1303 + eepromData[i] = eepromData[7 - i]; 1.1304 + eepromData[7 - i] = tmp; 1.1305 + i++; 1.1306 + tmp = eepromData[i]; 1.1307 + eepromData[i] = eepromData[7 - i]; 1.1308 + eepromData[7 - i] = tmp; 1.1309 + i++; 1.1310 + tmp = eepromData[i]; 1.1311 + eepromData[i] = eepromData[7 - i]; 1.1312 + eepromData[7 - i] = tmp; 1.1313 + i++; 1.1314 + tmp = eepromData[i]; 1.1315 + eepromData[i] = eepromData[7 - i]; 1.1316 + eepromData[7 - i] = tmp; 1.1317 + i++; 1.1318 + i += 4; 1.1319 + } 1.1320 + } 1.1321 + else 1.1322 + { 1.1323 + fclose(file); 1.1324 + return false; 1.1325 + } 1.1326 + fclose(file); 1.1327 + return true; 1.1328 +} 1.1329 + 1.1330 +bool CPUReadBatteryFromStream(gzFile gzFile) 1.1331 +{ 1.1332 + if (!gzFile) 1.1333 + return false; 1.1334 + 1.1335 + int version = utilReadInt(gzFile); 1.1336 + 1.1337 + // for simplicity, we put both types of battery files should be in the stream, even if one's empty 1.1338 + eepromReadGame(gzFile, version); 1.1339 + flashReadGame(gzFile, version); 1.1340 + 1.1341 + return true; 1.1342 +} 1.1343 + 1.1344 +bool CPUReadBatteryFile(const char *fileName) 1.1345 +{ 1.1346 + FILE *file = fopen(fileName, "rb"); 1.1347 + 1.1348 + if (!file) 1.1349 + return false; 1.1350 + 1.1351 + // check file size to know what we should read 1.1352 + fseek(file, 0, SEEK_END); 1.1353 + 1.1354 + long size = ftell(file); 1.1355 + fseek(file, 0, SEEK_SET); 1.1356 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 1.1357 + 1.1358 + if (size == 512 || size == 0x2000) 1.1359 + { 1.1360 + if (fread(eepromData, 1, size, file) != (size_t)size) 1.1361 + { 1.1362 + fclose(file); 1.1363 + return false; 1.1364 + } 1.1365 + } 1.1366 + else 1.1367 + { 1.1368 + if (size == 0x20000) 1.1369 + { 1.1370 + if (fread(flashSaveMemory, 1, 0x20000, file) != 0x20000) 1.1371 + { 1.1372 + fclose(file); 1.1373 + return false; 1.1374 + } 1.1375 + flashSetSize(0x20000); 1.1376 + } 1.1377 + else 1.1378 + { 1.1379 + if (fread(flashSaveMemory, 1, 0x10000, file) != 0x10000) 1.1380 + { 1.1381 + fclose(file); 1.1382 + return false; 1.1383 + } 1.1384 + flashSetSize(0x10000); 1.1385 + } 1.1386 + } 1.1387 + fclose(file); 1.1388 + return true; 1.1389 +} 1.1390 + 1.1391 +bool CPUWritePNGFile(const char *fileName) 1.1392 +{ 1.1393 + return utilWritePNGFile(fileName, 240, 160, pix); 1.1394 +} 1.1395 + 1.1396 +bool CPUWriteBMPFile(const char *fileName) 1.1397 +{ 1.1398 + return utilWriteBMPFile(fileName, 240, 160, pix); 1.1399 +} 1.1400 + 1.1401 +void CPUCleanUp() 1.1402 +{ 1.1403 + newFrame = true; 1.1404 + 1.1405 + GBASystemCounters.frameCount = 0; 1.1406 + GBASystemCounters.lagCount = 0; 1.1407 + GBASystemCounters.extraCount = 0; 1.1408 + GBASystemCounters.lagged = true; 1.1409 + GBASystemCounters.laggedLast = true; 1.1410 + 1.1411 +#ifdef PROFILING 1.1412 + if (profilingTicksReload) 1.1413 + { 1.1414 + profCleanup(); 1.1415 + } 1.1416 +#endif 1.1417 + 1.1418 +#if (defined(WIN32) && !defined(SDL)) 1.1419 + #define FreeMappedMem(name, mapName, offset) \ 1.1420 + if (name != NULL) { \ 1.1421 + UnmapViewOfFile((name) - (offset)); \ 1.1422 + name = NULL; \ 1.1423 + CloseHandle(mapName); \ 1.1424 + } 1.1425 +#else 1.1426 + #define FreeMappedMem(name, mapName, offset) \ 1.1427 + if (name != NULL) { \ 1.1428 + free(name); \ 1.1429 + name = NULL; \ 1.1430 + } 1.1431 +#endif 1.1432 + 1.1433 + FreeMappedMem(rom, mapROM, 0); 1.1434 + FreeMappedMem(vram, mapVRAM, 0); 1.1435 + FreeMappedMem(paletteRAM, mapPALETTERAM, 0); 1.1436 + FreeMappedMem(internalRAM, mapIRAM, 0); 1.1437 + FreeMappedMem(workRAM, mapWORKRAM, 0); 1.1438 + FreeMappedMem(bios, mapBIOS, 0); 1.1439 + FreeMappedMem(pix, mapPIX, 4); 1.1440 + FreeMappedMem(oam, mapOAM, 0); 1.1441 + FreeMappedMem(ioMem, mapIOMEM, 0); 1.1442 + 1.1443 + eepromErase(); 1.1444 + flashErase(); 1.1445 + 1.1446 + elfCleanUp(); 1.1447 + 1.1448 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 1.1449 + 1.1450 + systemClearJoypads(); 1.1451 + systemResetSensor(); 1.1452 + 1.1453 +// gbaLastTime = gbaFrameCount = 0; 1.1454 + systemRefreshScreen(); 1.1455 +} 1.1456 + 1.1457 +int CPULoadRom(const char *szFile) 1.1458 +{ 1.1459 + int size = 0x2000000; 1.1460 + 1.1461 + if (rom != NULL) 1.1462 + { 1.1463 + CPUCleanUp(); 1.1464 + } 1.1465 + 1.1466 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 1.1467 + 1.1468 + // size+4 is so RAM search and watch are safe to read any byte in the allocated region as a 4-byte int 1.1469 +#if (defined(WIN32) && !defined(SDL)) 1.1470 + #define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \ 1.1471 + mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), nameStr); \ 1.1472 + if ((mapName) && GetLastError() == ERROR_ALREADY_EXISTS) { \ 1.1473 + CloseHandle(mapName); \ 1.1474 + mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), NULL); \ 1.1475 + } \ 1.1476 + name = (u8 *)MapViewOfFile(mapName, FILE_MAP_WRITE, 0, 0, 0) + (offset); \ 1.1477 + if ((name) == NULL) { \ 1.1478 + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \ 1.1479 + CPUCleanUp(); \ 1.1480 + return 0; \ 1.1481 + } \ 1.1482 + memset(name, 0, size + 4); 1.1483 +#else 1.1484 + #define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \ 1.1485 + name = (u8 *)(useCalloc ? calloc(1, size + 4) : malloc(size + 4)); \ 1.1486 + if ((name) == NULL) { \ 1.1487 + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \ 1.1488 + CPUCleanUp(); \ 1.1489 + return 0; \ 1.1490 + } \ 1.1491 + memset(name, 0, size + 4); 1.1492 +#endif 1.1493 + 1.1494 + AllocMappedMem(rom, mapROM, "vbaROM", 0x2000000, false, 0); 1.1495 + AllocMappedMem(workRAM, mapWORKRAM, "vbaWORKRAM", 0x40000, true, 0); 1.1496 + 1.1497 + u8 *whereToLoad = rom; 1.1498 + if (cpuIsMultiBoot) 1.1499 + whereToLoad = workRAM; 1.1500 + 1.1501 + if (utilIsELF(szFile)) 1.1502 + { 1.1503 + FILE *f = fopen(szFile, "rb"); 1.1504 + if (!f) 1.1505 + { 1.1506 + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), 1.1507 + szFile); 1.1508 + FreeMappedMem(rom, mapROM, 0); 1.1509 + FreeMappedMem(workRAM, mapWORKRAM, 0); 1.1510 + return 0; 1.1511 + } 1.1512 + bool res = elfRead(szFile, size, f); 1.1513 + if (!res || size == 0) 1.1514 + { 1.1515 + FreeMappedMem(rom, mapROM, 0); 1.1516 + FreeMappedMem(workRAM, mapWORKRAM, 0); 1.1517 + elfCleanUp(); 1.1518 + return 0; 1.1519 + } 1.1520 + } 1.1521 + else if (!utilLoad(szFile, 1.1522 + utilIsGBAImage, 1.1523 + whereToLoad, 1.1524 + size)) 1.1525 + { 1.1526 + FreeMappedMem(rom, mapROM, 0); 1.1527 + FreeMappedMem(workRAM, mapWORKRAM, 0); 1.1528 + return 0; 1.1529 + } 1.1530 + 1.1531 + u16 *temp = (u16 *)(rom + ((size + 1) & ~1)); 1.1532 + int i; 1.1533 + for (i = (size + 1) & ~1; i < 0x2000000; i += 2) 1.1534 + { 1.1535 + WRITE16LE(temp, (i >> 1) & 0xFFFF); 1.1536 + temp++; 1.1537 + } 1.1538 + 1.1539 + AllocMappedMem(bios, mapBIOS, "vbaBIOS", 0x4000, true, 0); 1.1540 + AllocMappedMem(internalRAM, mapIRAM, "vbaIRAM", 0x8000, true, 0); 1.1541 + AllocMappedMem(paletteRAM, mapPALETTERAM, "vbaPALETTERAM", 0x400, true, 0); 1.1542 + AllocMappedMem(vram, mapVRAM, "vbaVRAM", 0x20000, true, 0); 1.1543 + AllocMappedMem(oam, mapOAM, "vbaOAM", 0x400, true, 0); 1.1544 + 1.1545 + // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel 1.1546 + AllocMappedMem(pix, mapPIX, "vbaPIX", 4 * 241 * 162, true, 4); 1.1547 + AllocMappedMem(ioMem, mapIOMEM, "vbaIOMEM", 0x400, true, 0); 1.1548 + 1.1549 + CPUUpdateRenderBuffers(true); 1.1550 + 1.1551 + return size; 1.1552 +} 1.1553 + 1.1554 +void CPUUpdateRender() 1.1555 +{ 1.1556 + switch (DISPCNT & 7) 1.1557 + { 1.1558 + case 0: 1.1559 + if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || 1.1560 + cpuDisableSfx) 1.1561 + renderLine = mode0RenderLine; 1.1562 + else if (fxOn && !windowOn && !(layerEnable & 0x8000)) 1.1563 + renderLine = mode0RenderLineNoWindow; 1.1564 + else 1.1565 + renderLine = mode0RenderLineAll; 1.1566 + break; 1.1567 + case 1: 1.1568 + if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || 1.1569 + cpuDisableSfx) 1.1570 + renderLine = mode1RenderLine; 1.1571 + else if (fxOn && !windowOn && !(layerEnable & 0x8000)) 1.1572 + renderLine = mode1RenderLineNoWindow; 1.1573 + else 1.1574 + renderLine = mode1RenderLineAll; 1.1575 + break; 1.1576 + case 2: 1.1577 + if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || 1.1578 + cpuDisableSfx) 1.1579 + renderLine = mode2RenderLine; 1.1580 + else if (fxOn && !windowOn && !(layerEnable & 0x8000)) 1.1581 + renderLine = mode2RenderLineNoWindow; 1.1582 + else 1.1583 + renderLine = mode2RenderLineAll; 1.1584 + break; 1.1585 + case 3: 1.1586 + if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || 1.1587 + cpuDisableSfx) 1.1588 + renderLine = mode3RenderLine; 1.1589 + else if (fxOn && !windowOn && !(layerEnable & 0x8000)) 1.1590 + renderLine = mode3RenderLineNoWindow; 1.1591 + else 1.1592 + renderLine = mode3RenderLineAll; 1.1593 + break; 1.1594 + case 4: 1.1595 + if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || 1.1596 + cpuDisableSfx) 1.1597 + renderLine = mode4RenderLine; 1.1598 + else if (fxOn && !windowOn && !(layerEnable & 0x8000)) 1.1599 + renderLine = mode4RenderLineNoWindow; 1.1600 + else 1.1601 + renderLine = mode4RenderLineAll; 1.1602 + break; 1.1603 + case 5: 1.1604 + if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || 1.1605 + cpuDisableSfx) 1.1606 + renderLine = mode5RenderLine; 1.1607 + else if (fxOn && !windowOn && !(layerEnable & 0x8000)) 1.1608 + renderLine = mode5RenderLineNoWindow; 1.1609 + else 1.1610 + renderLine = mode5RenderLineAll; 1.1611 + default: 1.1612 + break; 1.1613 + } 1.1614 +} 1.1615 + 1.1616 +void CPUUpdateCPSR() 1.1617 +{ 1.1618 + u32 CPSR = reg[16].I & 0x40; 1.1619 + if (N_FLAG) 1.1620 + CPSR |= 0x80000000; 1.1621 + if (Z_FLAG) 1.1622 + CPSR |= 0x40000000; 1.1623 + if (C_FLAG) 1.1624 + CPSR |= 0x20000000; 1.1625 + if (V_FLAG) 1.1626 + CPSR |= 0x10000000; 1.1627 + if (!armState) 1.1628 + CPSR |= 0x00000020; 1.1629 + if (!armIrqEnable) 1.1630 + CPSR |= 0x80; 1.1631 + CPSR |= (armMode & 0x1F); 1.1632 + reg[16].I = CPSR; 1.1633 +} 1.1634 + 1.1635 +void CPUUpdateFlags(bool breakLoop) 1.1636 +{ 1.1637 + u32 CPSR = reg[16].I; 1.1638 + 1.1639 + N_FLAG = (CPSR & 0x80000000) ? true : false; 1.1640 + Z_FLAG = (CPSR & 0x40000000) ? true : false; 1.1641 + C_FLAG = (CPSR & 0x20000000) ? true : false; 1.1642 + V_FLAG = (CPSR & 0x10000000) ? true : false; 1.1643 + armState = (CPSR & 0x20) ? false : true; 1.1644 + armIrqEnable = (CPSR & 0x80) ? false : true; 1.1645 + if (breakLoop) 1.1646 + { 1.1647 + if (armIrqEnable && (IF & IE) && (IME & 1)) 1.1648 + { 1.1649 + CPU_BREAK_LOOP_2; 1.1650 + } 1.1651 + } 1.1652 +} 1.1653 + 1.1654 +void CPUUpdateFlags() 1.1655 +{ 1.1656 + CPUUpdateFlags(true); 1.1657 +} 1.1658 + 1.1659 +#ifdef WORDS_BIGENDIAN 1.1660 +static void CPUSwap(volatile u32 *a, volatile u32 *b) 1.1661 +{ 1.1662 + volatile u32 c = *b; 1.1663 + *b = *a; 1.1664 + *a = c; 1.1665 +} 1.1666 + 1.1667 +#else 1.1668 +static void CPUSwap(u32 *a, u32 *b) 1.1669 +{ 1.1670 + u32 c = *b; 1.1671 + *b = *a; 1.1672 + *a = c; 1.1673 +} 1.1674 + 1.1675 +#endif 1.1676 + 1.1677 +void CPUSwitchMode(int mode, bool saveState, bool breakLoop) 1.1678 +{ 1.1679 + // if(armMode == mode) 1.1680 + // return; 1.1681 + 1.1682 + CPUUpdateCPSR(); 1.1683 + 1.1684 + switch (armMode) 1.1685 + { 1.1686 + case 0x10: 1.1687 + case 0x1F: 1.1688 + reg[R13_USR].I = reg[13].I; 1.1689 + reg[R14_USR].I = reg[14].I; 1.1690 + reg[17].I = reg[16].I; 1.1691 + break; 1.1692 + case 0x11: 1.1693 + CPUSwap(®[R8_FIQ].I, ®[8].I); 1.1694 + CPUSwap(®[R9_FIQ].I, ®[9].I); 1.1695 + CPUSwap(®[R10_FIQ].I, ®[10].I); 1.1696 + CPUSwap(®[R11_FIQ].I, ®[11].I); 1.1697 + CPUSwap(®[R12_FIQ].I, ®[12].I); 1.1698 + reg[R13_FIQ].I = reg[13].I; 1.1699 + reg[R14_FIQ].I = reg[14].I; 1.1700 + reg[SPSR_FIQ].I = reg[17].I; 1.1701 + break; 1.1702 + case 0x12: 1.1703 + reg[R13_IRQ].I = reg[13].I; 1.1704 + reg[R14_IRQ].I = reg[14].I; 1.1705 + reg[SPSR_IRQ].I = reg[17].I; 1.1706 + break; 1.1707 + case 0x13: 1.1708 + reg[R13_SVC].I = reg[13].I; 1.1709 + reg[R14_SVC].I = reg[14].I; 1.1710 + reg[SPSR_SVC].I = reg[17].I; 1.1711 + break; 1.1712 + case 0x17: 1.1713 + reg[R13_ABT].I = reg[13].I; 1.1714 + reg[R14_ABT].I = reg[14].I; 1.1715 + reg[SPSR_ABT].I = reg[17].I; 1.1716 + break; 1.1717 + case 0x1b: 1.1718 + reg[R13_UND].I = reg[13].I; 1.1719 + reg[R14_UND].I = reg[14].I; 1.1720 + reg[SPSR_UND].I = reg[17].I; 1.1721 + break; 1.1722 + } 1.1723 + 1.1724 + u32 CPSR = reg[16].I; 1.1725 + u32 SPSR = reg[17].I; 1.1726 + 1.1727 + switch (mode) 1.1728 + { 1.1729 + case 0x10: 1.1730 + case 0x1F: 1.1731 + reg[13].I = reg[R13_USR].I; 1.1732 + reg[14].I = reg[R14_USR].I; 1.1733 + reg[16].I = SPSR; 1.1734 + break; 1.1735 + case 0x11: 1.1736 + CPUSwap(®[8].I, ®[R8_FIQ].I); 1.1737 + CPUSwap(®[9].I, ®[R9_FIQ].I); 1.1738 + CPUSwap(®[10].I, ®[R10_FIQ].I); 1.1739 + CPUSwap(®[11].I, ®[R11_FIQ].I); 1.1740 + CPUSwap(®[12].I, ®[R12_FIQ].I); 1.1741 + reg[13].I = reg[R13_FIQ].I; 1.1742 + reg[14].I = reg[R14_FIQ].I; 1.1743 + if (saveState) 1.1744 + reg[17].I = CPSR; 1.1745 + else 1.1746 + reg[17].I = reg[SPSR_FIQ].I; 1.1747 + break; 1.1748 + case 0x12: 1.1749 + reg[13].I = reg[R13_IRQ].I; 1.1750 + reg[14].I = reg[R14_IRQ].I; 1.1751 + reg[16].I = SPSR; 1.1752 + if (saveState) 1.1753 + reg[17].I = CPSR; 1.1754 + else 1.1755 + reg[17].I = reg[SPSR_IRQ].I; 1.1756 + break; 1.1757 + case 0x13: 1.1758 + reg[13].I = reg[R13_SVC].I; 1.1759 + reg[14].I = reg[R14_SVC].I; 1.1760 + reg[16].I = SPSR; 1.1761 + if (saveState) 1.1762 + reg[17].I = CPSR; 1.1763 + else 1.1764 + reg[17].I = reg[SPSR_SVC].I; 1.1765 + break; 1.1766 + case 0x17: 1.1767 + reg[13].I = reg[R13_ABT].I; 1.1768 + reg[14].I = reg[R14_ABT].I; 1.1769 + reg[16].I = SPSR; 1.1770 + if (saveState) 1.1771 + reg[17].I = CPSR; 1.1772 + else 1.1773 + reg[17].I = reg[SPSR_ABT].I; 1.1774 + break; 1.1775 + case 0x1b: 1.1776 + reg[13].I = reg[R13_UND].I; 1.1777 + reg[14].I = reg[R14_UND].I; 1.1778 + reg[16].I = SPSR; 1.1779 + if (saveState) 1.1780 + reg[17].I = CPSR; 1.1781 + else 1.1782 + reg[17].I = reg[SPSR_UND].I; 1.1783 + break; 1.1784 + default: 1.1785 + systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode); 1.1786 + break; 1.1787 + } 1.1788 + armMode = mode; 1.1789 + CPUUpdateFlags(breakLoop); 1.1790 + CPUUpdateCPSR(); 1.1791 +} 1.1792 + 1.1793 +void CPUSwitchMode(int mode, bool saveState) 1.1794 +{ 1.1795 + CPUSwitchMode(mode, saveState, true); 1.1796 +} 1.1797 + 1.1798 +void CPUUndefinedException() 1.1799 +{ 1.1800 + u32 PC = reg[15].I; 1.1801 + bool savedArmState = armState; 1.1802 + CPUSwitchMode(0x1b, true, false); 1.1803 + reg[14].I = PC - (savedArmState ? 4 : 2); 1.1804 + reg[15].I = 0x04; 1.1805 + armState = true; 1.1806 + armIrqEnable = false; 1.1807 + armNextPC = 0x04; 1.1808 + reg[15].I += 4; 1.1809 +} 1.1810 + 1.1811 +void CPUSoftwareInterrupt() 1.1812 +{ 1.1813 + u32 PC = reg[15].I; 1.1814 + bool savedArmState = armState; 1.1815 + CPUSwitchMode(0x13, true, false); 1.1816 + reg[14].I = PC - (savedArmState ? 4 : 2); 1.1817 + reg[15].I = 0x08; 1.1818 + armState = true; 1.1819 + armIrqEnable = false; 1.1820 + armNextPC = 0x08; 1.1821 + reg[15].I += 4; 1.1822 +} 1.1823 + 1.1824 +void CPUSoftwareInterrupt(int comment) 1.1825 +{ 1.1826 + static bool disableMessage = false; 1.1827 + if (armState) 1.1828 + comment >>= 16; 1.1829 +#ifdef BKPT_SUPPORT 1.1830 + if (comment == 0xff) 1.1831 + { 1.1832 + extern void (*dbgOutput)(char *, u32); 1.1833 + dbgOutput(NULL, reg[0].I); 1.1834 + return; 1.1835 + } 1.1836 +#endif 1.1837 +#ifdef PROFILING 1.1838 + if (comment == 0xfe) 1.1839 + { 1.1840 + profStartup(reg[0].I, reg[1].I); 1.1841 + return; 1.1842 + } 1.1843 + if (comment == 0xfd) 1.1844 + { 1.1845 + profControl(reg[0].I); 1.1846 + return; 1.1847 + } 1.1848 + if (comment == 0xfc) 1.1849 + { 1.1850 + profCleanup(); 1.1851 + return; 1.1852 + } 1.1853 + if (comment == 0xfb) 1.1854 + { 1.1855 + profCount(); 1.1856 + return; 1.1857 + } 1.1858 +#endif 1.1859 + if (comment == 0xfa) 1.1860 + { 1.1861 + agbPrintFlush(); 1.1862 + return; 1.1863 + } 1.1864 +#ifdef SDL 1.1865 + if (comment == 0xf9) 1.1866 + { 1.1867 + emulating = 0; 1.1868 + CPU_BREAK_LOOP_2; 1.1869 + return; 1.1870 + } 1.1871 +#endif 1.1872 + if (useBios) 1.1873 + { 1.1874 +#ifdef GBA_LOGGING 1.1875 + if (systemVerbose & VERBOSE_SWI) 1.1876 + { 1.1877 + log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, 1.1878 + armState ? armNextPC - 4 : armNextPC - 2, 1.1879 + reg[0].I, 1.1880 + reg[1].I, 1.1881 + reg[2].I, 1.1882 + VCOUNT); 1.1883 + } 1.1884 +#endif 1.1885 + CPUSoftwareInterrupt(); 1.1886 + return; 1.1887 + } 1.1888 + // This would be correct, but it causes problems if uncommented 1.1889 + // else { 1.1890 + // biosProtected = 0xe3a02004; 1.1891 + // } 1.1892 + 1.1893 + switch (comment) 1.1894 + { 1.1895 + case 0x00: 1.1896 + BIOS_SoftReset(); 1.1897 + break; 1.1898 + case 0x01: 1.1899 + BIOS_RegisterRamReset(); 1.1900 + break; 1.1901 + case 0x02: 1.1902 +#ifdef GBA_LOGGING 1.1903 + if (systemVerbose & VERBOSE_SWI) 1.1904 + { 1.1905 + log("Halt: (VCOUNT = %2d)\n", 1.1906 + VCOUNT); 1.1907 + } 1.1908 +#endif 1.1909 + holdState = true; 1.1910 + holdType = -1; 1.1911 + break; 1.1912 + case 0x03: 1.1913 +#ifdef GBA_LOGGING 1.1914 + if (systemVerbose & VERBOSE_SWI) 1.1915 + { 1.1916 + log("Stop: (VCOUNT = %2d)\n", 1.1917 + VCOUNT); 1.1918 + } 1.1919 +#endif 1.1920 + holdState = true; 1.1921 + holdType = -1; 1.1922 + stopState = true; 1.1923 + break; 1.1924 + case 0x04: 1.1925 +#ifdef GBA_LOGGING 1.1926 + if (systemVerbose & VERBOSE_SWI) 1.1927 + { 1.1928 + log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n", 1.1929 + reg[0].I, 1.1930 + reg[1].I, 1.1931 + VCOUNT); 1.1932 + } 1.1933 +#endif 1.1934 + CPUSoftwareInterrupt(); 1.1935 + break; 1.1936 + case 0x05: 1.1937 +#ifdef GBA_LOGGING 1.1938 + if (systemVerbose & VERBOSE_SWI) 1.1939 + { 1.1940 + log("VBlankIntrWait: (VCOUNT = %2d)\n", 1.1941 + VCOUNT); 1.1942 + } 1.1943 +#endif 1.1944 + CPUSoftwareInterrupt(); 1.1945 + break; 1.1946 + case 0x06: 1.1947 + CPUSoftwareInterrupt(); 1.1948 + break; 1.1949 + case 0x07: 1.1950 + CPUSoftwareInterrupt(); 1.1951 + break; 1.1952 + case 0x08: 1.1953 + BIOS_Sqrt(); 1.1954 + break; 1.1955 + case 0x09: 1.1956 + BIOS_ArcTan(); 1.1957 + break; 1.1958 + case 0x0A: 1.1959 + BIOS_ArcTan2(); 1.1960 + break; 1.1961 + case 0x0B: 1.1962 + BIOS_CpuSet(); 1.1963 + break; 1.1964 + case 0x0C: 1.1965 + BIOS_CpuFastSet(); 1.1966 + break; 1.1967 + case 0x0E: 1.1968 + BIOS_BgAffineSet(); 1.1969 + break; 1.1970 + case 0x0F: 1.1971 + BIOS_ObjAffineSet(); 1.1972 + break; 1.1973 + case 0x10: 1.1974 + BIOS_BitUnPack(); 1.1975 + break; 1.1976 + case 0x11: 1.1977 + BIOS_LZ77UnCompWram(); 1.1978 + break; 1.1979 + case 0x12: 1.1980 + BIOS_LZ77UnCompVram(); 1.1981 + break; 1.1982 + case 0x13: 1.1983 + BIOS_HuffUnComp(); 1.1984 + break; 1.1985 + case 0x14: 1.1986 + BIOS_RLUnCompWram(); 1.1987 + break; 1.1988 + case 0x15: 1.1989 + BIOS_RLUnCompVram(); 1.1990 + break; 1.1991 + case 0x16: 1.1992 + BIOS_Diff8bitUnFilterWram(); 1.1993 + break; 1.1994 + case 0x17: 1.1995 + BIOS_Diff8bitUnFilterVram(); 1.1996 + break; 1.1997 + case 0x18: 1.1998 + BIOS_Diff16bitUnFilter(); 1.1999 + break; 1.2000 + case 0x19: 1.2001 +#ifdef GBA_LOGGING 1.2002 + if (systemVerbose & VERBOSE_SWI) 1.2003 + { 1.2004 + log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n", 1.2005 + reg[0].I, 1.2006 + VCOUNT); 1.2007 + } 1.2008 +#endif 1.2009 + if (reg[0].I) 1.2010 + soundPause(); 1.2011 + else 1.2012 + soundResume(); 1.2013 + break; 1.2014 + case 0x1F: 1.2015 + BIOS_MidiKey2Freq(); 1.2016 + break; 1.2017 + case 0x2A: 1.2018 + BIOS_SndDriverJmpTableCopy(); 1.2019 + // let it go, because we don't really emulate this function // FIXME (?) 1.2020 + default: 1.2021 +#ifdef GBA_LOGGING 1.2022 + if (systemVerbose & VERBOSE_SWI) 1.2023 + { 1.2024 + log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, 1.2025 + armState ? armNextPC - 4 : armNextPC - 2, 1.2026 + reg[0].I, 1.2027 + reg[1].I, 1.2028 + reg[2].I, 1.2029 + VCOUNT); 1.2030 + } 1.2031 +#endif 1.2032 + 1.2033 + if (!disableMessage) 1.2034 + { 1.2035 + systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION, 1.2036 + N_( 1.2037 + "Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."), 1.2038 + comment, 1.2039 + armMode ? armNextPC - 4 : armNextPC - 2); 1.2040 + disableMessage = true; 1.2041 + } 1.2042 + break; 1.2043 + } 1.2044 +} 1.2045 + 1.2046 +void CPUCompareVCOUNT() 1.2047 +{ 1.2048 + if (VCOUNT == (DISPSTAT >> 8)) 1.2049 + { 1.2050 + DISPSTAT |= 4; 1.2051 + UPDATE_REG(0x04, DISPSTAT); 1.2052 + 1.2053 + if (DISPSTAT & 0x20) 1.2054 + { 1.2055 + IF |= 4; 1.2056 + UPDATE_REG(0x202, IF); 1.2057 + } 1.2058 + } 1.2059 + else 1.2060 + { 1.2061 + DISPSTAT &= 0xFFFB; 1.2062 + UPDATE_REG(0x4, DISPSTAT); 1.2063 + } 1.2064 +} 1.2065 + 1.2066 +void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32) 1.2067 +{ 1.2068 + int sm = s >> 24; 1.2069 + int dm = d >> 24; 1.2070 + 1.2071 + int sc = c; 1.2072 + 1.2073 + cpuDmaCount = c; 1.2074 + 1.2075 + if (transfer32) 1.2076 + { 1.2077 + s &= 0xFFFFFFFC; 1.2078 + if (s < 0x02000000 && (reg[15].I >> 24)) 1.2079 + { 1.2080 + while (c != 0) 1.2081 + { 1.2082 + CPUWriteMemory(d, 0); 1.2083 + d += di; 1.2084 + c--; 1.2085 + } 1.2086 + } 1.2087 + else 1.2088 + { 1.2089 + while (c != 0) 1.2090 + { 1.2091 + CPUWriteMemory(d, CPUReadMemory(s)); 1.2092 + d += di; 1.2093 + s += si; 1.2094 + c--; 1.2095 + } 1.2096 + } 1.2097 + } 1.2098 + else 1.2099 + { 1.2100 + s &= 0xFFFFFFFE; 1.2101 + si = (int)si >> 1; 1.2102 + di = (int)di >> 1; 1.2103 + if (s < 0x02000000 && (reg[15].I >> 24)) 1.2104 + { 1.2105 + while (c != 0) 1.2106 + { 1.2107 + CPUWriteHalfWord(d, 0); 1.2108 + d += di; 1.2109 + c--; 1.2110 + } 1.2111 + } 1.2112 + else 1.2113 + { 1.2114 + while (c != 0) 1.2115 + { 1.2116 + cpuDmaLast = CPUReadHalfWord(s); 1.2117 + CPUWriteHalfWord(d, cpuDmaLast); 1.2118 + d += di; 1.2119 + s += si; 1.2120 + c--; 1.2121 + } 1.2122 + } 1.2123 + } 1.2124 + 1.2125 + cpuDmaCount = 0; 1.2126 + 1.2127 + int sw = 1 + memoryWaitSeq[sm & 15]; 1.2128 + int dw = 1 + memoryWaitSeq[dm & 15]; 1.2129 + 1.2130 + int totalTicks = 0; 1.2131 + 1.2132 + if (transfer32) 1.2133 + { 1.2134 + if (!memory32[sm & 15]) 1.2135 + sw <<= 1; 1.2136 + if (!memory32[dm & 15]) 1.2137 + dw <<= 1; 1.2138 + } 1.2139 + 1.2140 + totalTicks = (sw + dw) * sc; 1.2141 + 1.2142 + cpuDmaTicksToUpdate += totalTicks; 1.2143 + 1.2144 + if (*extCpuLoopTicks >= 0) 1.2145 + { 1.2146 + CPU_BREAK_LOOP; 1.2147 + } 1.2148 +} 1.2149 + 1.2150 +void CPUCheckDMA(int reason, int dmamask) 1.2151 +{ 1.2152 + cpuDmaHack = 0; 1.2153 + // DMA 0 1.2154 + if ((DM0CNT_H & 0x8000) && (dmamask & 1)) 1.2155 + { 1.2156 + if (((DM0CNT_H >> 12) & 3) == reason) 1.2157 + { 1.2158 + u32 sourceIncrement = 4; 1.2159 + u32 destIncrement = 4; 1.2160 + switch ((DM0CNT_H >> 7) & 3) 1.2161 + { 1.2162 + case 0: 1.2163 + break; 1.2164 + case 1: 1.2165 + sourceIncrement = (u32) - 4; 1.2166 + break; 1.2167 + case 2: 1.2168 + sourceIncrement = 0; 1.2169 + break; 1.2170 + } 1.2171 + switch ((DM0CNT_H >> 5) & 3) 1.2172 + { 1.2173 + case 0: 1.2174 + break; 1.2175 + case 1: 1.2176 + destIncrement = (u32) - 4; 1.2177 + break; 1.2178 + case 2: 1.2179 + destIncrement = 0; 1.2180 + break; 1.2181 + } 1.2182 +#ifdef GBA_LOGGING 1.2183 + if (systemVerbose & VERBOSE_DMA0) 1.2184 + { 1.2185 + int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1; 1.2186 + if (DM0CNT_H & 0x0400) 1.2187 + count <<= 1; 1.2188 + log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest, 1.2189 + DM0CNT_H, 1.2190 + count); 1.2191 + } 1.2192 +#endif 1.2193 + doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement, 1.2194 + DM0CNT_L ? DM0CNT_L : 0x4000, 1.2195 + DM0CNT_H & 0x0400); 1.2196 + cpuDmaHack = 1; 1.2197 + if (DM0CNT_H & 0x4000) 1.2198 + { 1.2199 + IF |= 0x0100; 1.2200 + UPDATE_REG(0x202, IF); 1.2201 + } 1.2202 + 1.2203 + if (((DM0CNT_H >> 5) & 3) == 3) 1.2204 + { 1.2205 + dma0Dest = DM0DAD_L | (DM0DAD_H << 16); 1.2206 + } 1.2207 + 1.2208 + if (!(DM0CNT_H & 0x0200) || (reason == 0)) 1.2209 + { 1.2210 + DM0CNT_H &= 0x7FFF; 1.2211 + UPDATE_REG(0xBA, DM0CNT_H); 1.2212 + } 1.2213 + } 1.2214 + } 1.2215 + 1.2216 + // DMA 1 1.2217 + if ((DM1CNT_H & 0x8000) && (dmamask & 2)) 1.2218 + { 1.2219 + if (((DM1CNT_H >> 12) & 3) == reason) 1.2220 + { 1.2221 + u32 sourceIncrement = 4; 1.2222 + u32 destIncrement = 4; 1.2223 + switch ((DM1CNT_H >> 7) & 3) 1.2224 + { 1.2225 + case 0: 1.2226 + break; 1.2227 + case 1: 1.2228 + sourceIncrement = (u32) - 4; 1.2229 + break; 1.2230 + case 2: 1.2231 + sourceIncrement = 0; 1.2232 + break; 1.2233 + } 1.2234 + switch ((DM1CNT_H >> 5) & 3) 1.2235 + { 1.2236 + case 0: 1.2237 + break; 1.2238 + case 1: 1.2239 + destIncrement = (u32) - 4; 1.2240 + break; 1.2241 + case 2: 1.2242 + destIncrement = 0; 1.2243 + break; 1.2244 + } 1.2245 + if (reason == 3) 1.2246 + { 1.2247 +#ifdef GBA_LOGGING 1.2248 + if (systemVerbose & VERBOSE_DMA1) 1.2249 + { 1.2250 + log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, 1.2251 + DM1CNT_H, 1.2252 + 16); 1.2253 + } 1.2254 +#endif 1.2255 + doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4, 1.2256 + 0x0400); 1.2257 + } 1.2258 + else 1.2259 + { 1.2260 +#ifdef GBA_LOGGING 1.2261 + if (systemVerbose & VERBOSE_DMA1) 1.2262 + { 1.2263 + int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1; 1.2264 + if (DM1CNT_H & 0x0400) 1.2265 + count <<= 1; 1.2266 + log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, 1.2267 + DM1CNT_H, 1.2268 + count); 1.2269 + } 1.2270 +#endif 1.2271 + doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement, 1.2272 + DM1CNT_L ? DM1CNT_L : 0x4000, 1.2273 + DM1CNT_H & 0x0400); 1.2274 + } 1.2275 + cpuDmaHack = 1; 1.2276 + 1.2277 + if (DM1CNT_H & 0x4000) 1.2278 + { 1.2279 + IF |= 0x0200; 1.2280 + UPDATE_REG(0x202, IF); 1.2281 + } 1.2282 + 1.2283 + if (((DM1CNT_H >> 5) & 3) == 3) 1.2284 + { 1.2285 + dma1Dest = DM1DAD_L | (DM1DAD_H << 16); 1.2286 + } 1.2287 + 1.2288 + if (!(DM1CNT_H & 0x0200) || (reason == 0)) 1.2289 + { 1.2290 + DM1CNT_H &= 0x7FFF; 1.2291 + UPDATE_REG(0xC6, DM1CNT_H); 1.2292 + } 1.2293 + } 1.2294 + } 1.2295 + 1.2296 + // DMA 2 1.2297 + if ((DM2CNT_H & 0x8000) && (dmamask & 4)) 1.2298 + { 1.2299 + if (((DM2CNT_H >> 12) & 3) == reason) 1.2300 + { 1.2301 + u32 sourceIncrement = 4; 1.2302 + u32 destIncrement = 4; 1.2303 + switch ((DM2CNT_H >> 7) & 3) 1.2304 + { 1.2305 + case 0: 1.2306 + break; 1.2307 + case 1: 1.2308 + sourceIncrement = (u32) - 4; 1.2309 + break; 1.2310 + case 2: 1.2311 + sourceIncrement = 0; 1.2312 + break; 1.2313 + } 1.2314 + switch ((DM2CNT_H >> 5) & 3) 1.2315 + { 1.2316 + case 0: 1.2317 + break; 1.2318 + case 1: 1.2319 + destIncrement = (u32) - 4; 1.2320 + break; 1.2321 + case 2: 1.2322 + destIncrement = 0; 1.2323 + break; 1.2324 + } 1.2325 + if (reason == 3) 1.2326 + { 1.2327 +#ifdef GBA_LOGGING 1.2328 + if (systemVerbose & VERBOSE_DMA2) 1.2329 + { 1.2330 + int count = (4) << 2; 1.2331 + log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, 1.2332 + DM2CNT_H, 1.2333 + count); 1.2334 + } 1.2335 +#endif 1.2336 + doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4, 1.2337 + 0x0400); 1.2338 + } 1.2339 + else 1.2340 + { 1.2341 +#ifdef GBA_LOGGING 1.2342 + if (systemVerbose & VERBOSE_DMA2) 1.2343 + { 1.2344 + int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1; 1.2345 + if (DM2CNT_H & 0x0400) 1.2346 + count <<= 1; 1.2347 + log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, 1.2348 + DM2CNT_H, 1.2349 + count); 1.2350 + } 1.2351 +#endif 1.2352 + doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement, 1.2353 + DM2CNT_L ? DM2CNT_L : 0x4000, 1.2354 + DM2CNT_H & 0x0400); 1.2355 + } 1.2356 + cpuDmaHack = 1; 1.2357 + if (DM2CNT_H & 0x4000) 1.2358 + { 1.2359 + IF |= 0x0400; 1.2360 + UPDATE_REG(0x202, IF); 1.2361 + } 1.2362 + 1.2363 + if (((DM2CNT_H >> 5) & 3) == 3) 1.2364 + { 1.2365 + dma2Dest = DM2DAD_L | (DM2DAD_H << 16); 1.2366 + } 1.2367 + 1.2368 + if (!(DM2CNT_H & 0x0200) || (reason == 0)) 1.2369 + { 1.2370 + DM2CNT_H &= 0x7FFF; 1.2371 + UPDATE_REG(0xD2, DM2CNT_H); 1.2372 + } 1.2373 + } 1.2374 + } 1.2375 + 1.2376 + // DMA 3 1.2377 + if ((DM3CNT_H & 0x8000) && (dmamask & 8)) 1.2378 + { 1.2379 + if (((DM3CNT_H >> 12) & 3) == reason) 1.2380 + { 1.2381 + u32 sourceIncrement = 4; 1.2382 + u32 destIncrement = 4; 1.2383 + switch ((DM3CNT_H >> 7) & 3) 1.2384 + { 1.2385 + case 0: 1.2386 + break; 1.2387 + case 1: 1.2388 + sourceIncrement = (u32) - 4; 1.2389 + break; 1.2390 + case 2: 1.2391 + sourceIncrement = 0; 1.2392 + break; 1.2393 + } 1.2394 + switch ((DM3CNT_H >> 5) & 3) 1.2395 + { 1.2396 + case 0: 1.2397 + break; 1.2398 + case 1: 1.2399 + destIncrement = (u32) - 4; 1.2400 + break; 1.2401 + case 2: 1.2402 + destIncrement = 0; 1.2403 + break; 1.2404 + } 1.2405 +#ifdef GBA_LOGGING 1.2406 + if (systemVerbose & VERBOSE_DMA3) 1.2407 + { 1.2408 + int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1; 1.2409 + if (DM3CNT_H & 0x0400) 1.2410 + count <<= 1; 1.2411 + log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest, 1.2412 + DM3CNT_H, 1.2413 + count); 1.2414 + } 1.2415 +#endif 1.2416 + doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement, 1.2417 + DM3CNT_L ? DM3CNT_L : 0x10000, 1.2418 + DM3CNT_H & 0x0400); 1.2419 + if (DM3CNT_H & 0x4000) 1.2420 + { 1.2421 + IF |= 0x0800; 1.2422 + UPDATE_REG(0x202, IF); 1.2423 + } 1.2424 + 1.2425 + if (((DM3CNT_H >> 5) & 3) == 3) 1.2426 + { 1.2427 + dma3Dest = DM3DAD_L | (DM3DAD_H << 16); 1.2428 + } 1.2429 + 1.2430 + if (!(DM3CNT_H & 0x0200) || (reason == 0)) 1.2431 + { 1.2432 + DM3CNT_H &= 0x7FFF; 1.2433 + UPDATE_REG(0xDE, DM3CNT_H); 1.2434 + } 1.2435 + } 1.2436 + } 1.2437 + cpuDmaHack = 0; 1.2438 +} 1.2439 + 1.2440 +void CPUUpdateRegister(u32 address, u16 value) 1.2441 +{ 1.2442 + switch (address) 1.2443 + { 1.2444 + case 0x00: 1.2445 + { 1.2446 + bool change = ((DISPCNT ^ value) & 0x80) ? true : false; 1.2447 + bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false; 1.2448 + DISPCNT = (value & 0xFFF7); 1.2449 + UPDATE_REG(0x00, DISPCNT); 1.2450 + layerEnable = layerSettings & value; 1.2451 + windowOn = (layerEnable & 0x6000) ? true : false; 1.2452 + if (change && !((value & 0x80))) 1.2453 + { 1.2454 + if (!(DISPSTAT & 1)) 1.2455 + { 1.2456 + lcdTicks = 960; 1.2457 + // VCOUNT = 0; 1.2458 + // UPDATE_REG(0x06, VCOUNT); 1.2459 + DISPSTAT &= 0xFFFC; 1.2460 + UPDATE_REG(0x04, DISPSTAT); 1.2461 + CPUCompareVCOUNT(); 1.2462 + } 1.2463 + // (*renderLine)(); 1.2464 + } 1.2465 + CPUUpdateRender(); 1.2466 + // we only care about changes in BG0-BG3 1.2467 + if (changeBG) 1.2468 + CPUUpdateRenderBuffers(false); 1.2469 + // CPUUpdateTicks(); 1.2470 + break; 1.2471 + } 1.2472 + case 0x04: 1.2473 + DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7); 1.2474 + UPDATE_REG(0x04, DISPSTAT); 1.2475 + break; 1.2476 + case 0x06: 1.2477 + // not writable 1.2478 + break; 1.2479 + case 0x08: 1.2480 + BG0CNT = (value & 0xDFCF); 1.2481 + UPDATE_REG(0x08, BG0CNT); 1.2482 + break; 1.2483 + case 0x0A: 1.2484 + BG1CNT = (value & 0xDFCF); 1.2485 + UPDATE_REG(0x0A, BG1CNT); 1.2486 + break; 1.2487 + case 0x0C: 1.2488 + BG2CNT = (value & 0xFFCF); 1.2489 + UPDATE_REG(0x0C, BG2CNT); 1.2490 + break; 1.2491 + case 0x0E: 1.2492 + BG3CNT = (value & 0xFFCF); 1.2493 + UPDATE_REG(0x0E, BG3CNT); 1.2494 + break; 1.2495 + case 0x10: 1.2496 + BG0HOFS = value & 511; 1.2497 + UPDATE_REG(0x10, BG0HOFS); 1.2498 + break; 1.2499 + case 0x12: 1.2500 + BG0VOFS = value & 511; 1.2501 + UPDATE_REG(0x12, BG0VOFS); 1.2502 + break; 1.2503 + case 0x14: 1.2504 + BG1HOFS = value & 511; 1.2505 + UPDATE_REG(0x14, BG1HOFS); 1.2506 + break; 1.2507 + case 0x16: 1.2508 + BG1VOFS = value & 511; 1.2509 + UPDATE_REG(0x16, BG1VOFS); 1.2510 + break; 1.2511 + case 0x18: 1.2512 + BG2HOFS = value & 511; 1.2513 + UPDATE_REG(0x18, BG2HOFS); 1.2514 + break; 1.2515 + case 0x1A: 1.2516 + BG2VOFS = value & 511; 1.2517 + UPDATE_REG(0x1A, BG2VOFS); 1.2518 + break; 1.2519 + case 0x1C: 1.2520 + BG3HOFS = value & 511; 1.2521 + UPDATE_REG(0x1C, BG3HOFS); 1.2522 + break; 1.2523 + case 0x1E: 1.2524 + BG3VOFS = value & 511; 1.2525 + UPDATE_REG(0x1E, BG3VOFS); 1.2526 + break; 1.2527 + case 0x20: 1.2528 + BG2PA = value; 1.2529 + UPDATE_REG(0x20, BG2PA); 1.2530 + break; 1.2531 + case 0x22: 1.2532 + BG2PB = value; 1.2533 + UPDATE_REG(0x22, BG2PB); 1.2534 + break; 1.2535 + case 0x24: 1.2536 + BG2PC = value; 1.2537 + UPDATE_REG(0x24, BG2PC); 1.2538 + break; 1.2539 + case 0x26: 1.2540 + BG2PD = value; 1.2541 + UPDATE_REG(0x26, BG2PD); 1.2542 + break; 1.2543 + case 0x28: 1.2544 + BG2X_L = value; 1.2545 + UPDATE_REG(0x28, BG2X_L); 1.2546 + gfxBG2Changed |= 1; 1.2547 + break; 1.2548 + case 0x2A: 1.2549 + BG2X_H = (value & 0xFFF); 1.2550 + UPDATE_REG(0x2A, BG2X_H); 1.2551 + gfxBG2Changed |= 1; 1.2552 + break; 1.2553 + case 0x2C: 1.2554 + BG2Y_L = value; 1.2555 + UPDATE_REG(0x2C, BG2Y_L); 1.2556 + gfxBG2Changed |= 2; 1.2557 + break; 1.2558 + case 0x2E: 1.2559 + BG2Y_H = value & 0xFFF; 1.2560 + UPDATE_REG(0x2E, BG2Y_H); 1.2561 + gfxBG2Changed |= 2; 1.2562 + break; 1.2563 + case 0x30: 1.2564 + BG3PA = value; 1.2565 + UPDATE_REG(0x30, BG3PA); 1.2566 + break; 1.2567 + case 0x32: 1.2568 + BG3PB = value; 1.2569 + UPDATE_REG(0x32, BG3PB); 1.2570 + break; 1.2571 + case 0x34: 1.2572 + BG3PC = value; 1.2573 + UPDATE_REG(0x34, BG3PC); 1.2574 + break; 1.2575 + case 0x36: 1.2576 + BG3PD = value; 1.2577 + UPDATE_REG(0x36, BG3PD); 1.2578 + break; 1.2579 + case 0x38: 1.2580 + BG3X_L = value; 1.2581 + UPDATE_REG(0x38, BG3X_L); 1.2582 + gfxBG3Changed |= 1; 1.2583 + break; 1.2584 + case 0x3A: 1.2585 + BG3X_H = value & 0xFFF; 1.2586 + UPDATE_REG(0x3A, BG3X_H); 1.2587 + gfxBG3Changed |= 1; 1.2588 + break; 1.2589 + case 0x3C: 1.2590 + BG3Y_L = value; 1.2591 + UPDATE_REG(0x3C, BG3Y_L); 1.2592 + gfxBG3Changed |= 2; 1.2593 + break; 1.2594 + case 0x3E: 1.2595 + BG3Y_H = value & 0xFFF; 1.2596 + UPDATE_REG(0x3E, BG3Y_H); 1.2597 + gfxBG3Changed |= 2; 1.2598 + break; 1.2599 + case 0x40: 1.2600 + WIN0H = value; 1.2601 + UPDATE_REG(0x40, WIN0H); 1.2602 + CPUUpdateWindow0(); 1.2603 + break; 1.2604 + case 0x42: 1.2605 + WIN1H = value; 1.2606 + UPDATE_REG(0x42, WIN1H); 1.2607 + CPUUpdateWindow1(); 1.2608 + break; 1.2609 + case 0x44: 1.2610 + WIN0V = value; 1.2611 + UPDATE_REG(0x44, WIN0V); 1.2612 + break; 1.2613 + case 0x46: 1.2614 + WIN1V = value; 1.2615 + UPDATE_REG(0x46, WIN1V); 1.2616 + break; 1.2617 + case 0x48: 1.2618 + WININ = value & 0x3F3F; 1.2619 + UPDATE_REG(0x48, WININ); 1.2620 + break; 1.2621 + case 0x4A: 1.2622 + WINOUT = value & 0x3F3F; 1.2623 + UPDATE_REG(0x4A, WINOUT); 1.2624 + break; 1.2625 + case 0x4C: 1.2626 + MOSAIC = value; 1.2627 + UPDATE_REG(0x4C, MOSAIC); 1.2628 + break; 1.2629 + case 0x50: 1.2630 + BLDMOD = value & 0x3FFF; 1.2631 + UPDATE_REG(0x50, BLDMOD); 1.2632 + fxOn = ((BLDMOD >> 6) & 3) != 0; 1.2633 + CPUUpdateRender(); 1.2634 + break; 1.2635 + case 0x52: 1.2636 + COLEV = value & 0x1F1F; 1.2637 + UPDATE_REG(0x52, COLEV); 1.2638 + break; 1.2639 + case 0x54: 1.2640 + COLY = value & 0x1F; 1.2641 + UPDATE_REG(0x54, COLY); 1.2642 + break; 1.2643 + case 0x60: 1.2644 + case 0x62: 1.2645 + case 0x64: 1.2646 + case 0x68: 1.2647 + case 0x6c: 1.2648 + case 0x70: 1.2649 + case 0x72: 1.2650 + case 0x74: 1.2651 + case 0x78: 1.2652 + case 0x7c: 1.2653 + case 0x80: 1.2654 + case 0x84: 1.2655 + soundEvent(address & 0xFF, (u8)(value & 0xFF)); 1.2656 + soundEvent((address & 0xFF) + 1, (u8)(value >> 8)); 1.2657 + break; 1.2658 + case 0x82: 1.2659 + case 0x88: 1.2660 + case 0xa0: 1.2661 + case 0xa2: 1.2662 + case 0xa4: 1.2663 + case 0xa6: 1.2664 + case 0x90: 1.2665 + case 0x92: 1.2666 + case 0x94: 1.2667 + case 0x96: 1.2668 + case 0x98: 1.2669 + case 0x9a: 1.2670 + case 0x9c: 1.2671 + case 0x9e: 1.2672 + soundEvent(address & 0xFF, value); 1.2673 + break; 1.2674 + case 0xB0: 1.2675 + DM0SAD_L = value; 1.2676 + UPDATE_REG(0xB0, DM0SAD_L); 1.2677 + break; 1.2678 + case 0xB2: 1.2679 + DM0SAD_H = value & 0x07FF; 1.2680 + UPDATE_REG(0xB2, DM0SAD_H); 1.2681 + break; 1.2682 + case 0xB4: 1.2683 + DM0DAD_L = value; 1.2684 + UPDATE_REG(0xB4, DM0DAD_L); 1.2685 + break; 1.2686 + case 0xB6: 1.2687 + DM0DAD_H = value & 0x07FF; 1.2688 + UPDATE_REG(0xB6, DM0DAD_H); 1.2689 + break; 1.2690 + case 0xB8: 1.2691 + DM0CNT_L = value & 0x3FFF; 1.2692 + UPDATE_REG(0xB8, 0); 1.2693 + break; 1.2694 + case 0xBA: 1.2695 + { 1.2696 + bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false; 1.2697 + value &= 0xF7E0; 1.2698 + 1.2699 + DM0CNT_H = value; 1.2700 + UPDATE_REG(0xBA, DM0CNT_H); 1.2701 + 1.2702 + if (start && (value & 0x8000)) 1.2703 + { 1.2704 + dma0Source = DM0SAD_L | (DM0SAD_H << 16); 1.2705 + dma0Dest = DM0DAD_L | (DM0DAD_H << 16); 1.2706 + CPUCheckDMA(0, 1); 1.2707 + } 1.2708 + break; 1.2709 + } 1.2710 + case 0xBC: 1.2711 + DM1SAD_L = value; 1.2712 + UPDATE_REG(0xBC, DM1SAD_L); 1.2713 + break; 1.2714 + case 0xBE: 1.2715 + DM1SAD_H = value & 0x0FFF; 1.2716 + UPDATE_REG(0xBE, DM1SAD_H); 1.2717 + break; 1.2718 + case 0xC0: 1.2719 + DM1DAD_L = value; 1.2720 + UPDATE_REG(0xC0, DM1DAD_L); 1.2721 + break; 1.2722 + case 0xC2: 1.2723 + DM1DAD_H = value & 0x07FF; 1.2724 + UPDATE_REG(0xC2, DM1DAD_H); 1.2725 + break; 1.2726 + case 0xC4: 1.2727 + DM1CNT_L = value & 0x3FFF; 1.2728 + UPDATE_REG(0xC4, 0); 1.2729 + break; 1.2730 + case 0xC6: 1.2731 + { 1.2732 + bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false; 1.2733 + value &= 0xF7E0; 1.2734 + 1.2735 + DM1CNT_H = value; 1.2736 + UPDATE_REG(0xC6, DM1CNT_H); 1.2737 + 1.2738 + if (start && (value & 0x8000)) 1.2739 + { 1.2740 + dma1Source = DM1SAD_L | (DM1SAD_H << 16); 1.2741 + dma1Dest = DM1DAD_L | (DM1DAD_H << 16); 1.2742 + CPUCheckDMA(0, 2); 1.2743 + } 1.2744 + break; 1.2745 + } 1.2746 + case 0xC8: 1.2747 + DM2SAD_L = value; 1.2748 + UPDATE_REG(0xC8, DM2SAD_L); 1.2749 + break; 1.2750 + case 0xCA: 1.2751 + DM2SAD_H = value & 0x0FFF; 1.2752 + UPDATE_REG(0xCA, DM2SAD_H); 1.2753 + break; 1.2754 + case 0xCC: 1.2755 + DM2DAD_L = value; 1.2756 + UPDATE_REG(0xCC, DM2DAD_L); 1.2757 + break; 1.2758 + case 0xCE: 1.2759 + DM2DAD_H = value & 0x07FF; 1.2760 + UPDATE_REG(0xCE, DM2DAD_H); 1.2761 + break; 1.2762 + case 0xD0: 1.2763 + DM2CNT_L = value & 0x3FFF; 1.2764 + UPDATE_REG(0xD0, 0); 1.2765 + break; 1.2766 + case 0xD2: 1.2767 + { 1.2768 + bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false; 1.2769 + 1.2770 + value &= 0xF7E0; 1.2771 + 1.2772 + DM2CNT_H = value; 1.2773 + UPDATE_REG(0xD2, DM2CNT_H); 1.2774 + 1.2775 + if (start && (value & 0x8000)) 1.2776 + { 1.2777 + dma2Source = DM2SAD_L | (DM2SAD_H << 16); 1.2778 + dma2Dest = DM2DAD_L | (DM2DAD_H << 16); 1.2779 + 1.2780 + CPUCheckDMA(0, 4); 1.2781 + } 1.2782 + break; 1.2783 + } 1.2784 + case 0xD4: 1.2785 + DM3SAD_L = value; 1.2786 + UPDATE_REG(0xD4, DM3SAD_L); 1.2787 + break; 1.2788 + case 0xD6: 1.2789 + DM3SAD_H = value & 0x0FFF; 1.2790 + UPDATE_REG(0xD6, DM3SAD_H); 1.2791 + break; 1.2792 + case 0xD8: 1.2793 + DM3DAD_L = value; 1.2794 + UPDATE_REG(0xD8, DM3DAD_L); 1.2795 + break; 1.2796 + case 0xDA: 1.2797 + DM3DAD_H = value & 0x0FFF; 1.2798 + UPDATE_REG(0xDA, DM3DAD_H); 1.2799 + break; 1.2800 + case 0xDC: 1.2801 + DM3CNT_L = value; 1.2802 + UPDATE_REG(0xDC, 0); 1.2803 + break; 1.2804 + case 0xDE: 1.2805 + { 1.2806 + bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false; 1.2807 + 1.2808 + value &= 0xFFE0; 1.2809 + 1.2810 + DM3CNT_H = value; 1.2811 + UPDATE_REG(0xDE, DM3CNT_H); 1.2812 + 1.2813 + if (start && (value & 0x8000)) 1.2814 + { 1.2815 + dma3Source = DM3SAD_L | (DM3SAD_H << 16); 1.2816 + dma3Dest = DM3DAD_L | (DM3DAD_H << 16); 1.2817 + CPUCheckDMA(0, 8); 1.2818 + } 1.2819 + break; 1.2820 + } 1.2821 + case 0x100: 1.2822 + timer0Reload = value; 1.2823 + break; 1.2824 + case 0x102: 1.2825 + timer0Ticks = timer0ClockReload = TIMER_TICKS[value & 3]; 1.2826 + if (!timer0On && (value & 0x80)) 1.2827 + { 1.2828 + // reload the counter 1.2829 + TM0D = timer0Reload; 1.2830 + if (timer0ClockReload == 1) 1.2831 + timer0Ticks = 0x10000 - TM0D; 1.2832 + UPDATE_REG(0x100, TM0D); 1.2833 + } 1.2834 + timer0On = value & 0x80 ? true : false; 1.2835 + TM0CNT = value & 0xC7; 1.2836 + UPDATE_REG(0x102, TM0CNT); 1.2837 + // CPUUpdateTicks(); 1.2838 + break; 1.2839 + case 0x104: 1.2840 + timer1Reload = value; 1.2841 + break; 1.2842 + case 0x106: 1.2843 + timer1Ticks = timer1ClockReload = TIMER_TICKS[value & 3]; 1.2844 + if (!timer1On && (value & 0x80)) 1.2845 + { 1.2846 + // reload the counter 1.2847 + TM1D = timer1Reload; 1.2848 + if (timer1ClockReload == 1) 1.2849 + timer1Ticks = 0x10000 - TM1D; 1.2850 + UPDATE_REG(0x104, TM1D); 1.2851 + } 1.2852 + timer1On = value & 0x80 ? true : false; 1.2853 + TM1CNT = value & 0xC7; 1.2854 + UPDATE_REG(0x106, TM1CNT); 1.2855 + break; 1.2856 + case 0x108: 1.2857 + timer2Reload = value; 1.2858 + break; 1.2859 + case 0x10A: 1.2860 + timer2Ticks = timer2ClockReload = TIMER_TICKS[value & 3]; 1.2861 + if (!timer2On && (value & 0x80)) 1.2862 + { 1.2863 + // reload the counter 1.2864 + TM2D = timer2Reload; 1.2865 + if (timer2ClockReload == 1) 1.2866 + timer2Ticks = 0x10000 - TM2D; 1.2867 + UPDATE_REG(0x108, TM2D); 1.2868 + } 1.2869 + timer2On = value & 0x80 ? true : false; 1.2870 + TM2CNT = value & 0xC7; 1.2871 + UPDATE_REG(0x10A, TM2CNT); 1.2872 + break; 1.2873 + case 0x10C: 1.2874 + timer3Reload = value; 1.2875 + break; 1.2876 + case 0x10E: 1.2877 + timer3Ticks = timer3ClockReload = TIMER_TICKS[value & 3]; 1.2878 + if (!timer3On && (value & 0x80)) 1.2879 + { 1.2880 + // reload the counter 1.2881 + TM3D = timer3Reload; 1.2882 + if (timer3ClockReload == 1) 1.2883 + timer3Ticks = 0x10000 - TM3D; 1.2884 + UPDATE_REG(0x10C, TM3D); 1.2885 + } 1.2886 + timer3On = value & 0x80 ? true : false; 1.2887 + TM3CNT = value & 0xC7; 1.2888 + UPDATE_REG(0x10E, TM3CNT); 1.2889 + break; 1.2890 + case 0x128: 1.2891 + if (value & 0x80) 1.2892 + { 1.2893 + value &= 0xff7f; 1.2894 + if (value & 1 && (value & 0x4000)) 1.2895 + { 1.2896 + UPDATE_REG(0x12a, 0xFF); 1.2897 + IF |= 0x80; 1.2898 + UPDATE_REG(0x202, IF); 1.2899 + value &= 0x7f7f; 1.2900 + } 1.2901 + } 1.2902 + UPDATE_REG(0x128, value); 1.2903 + break; 1.2904 + case 0x130: 1.2905 + P1 |= (value & 0x3FF); 1.2906 + UPDATE_REG(0x130, P1); 1.2907 + break; 1.2908 + case 0x132: 1.2909 + UPDATE_REG(0x132, value & 0xC3FF); 1.2910 + break; 1.2911 + case 0x200: 1.2912 + IE = value & 0x3FFF; 1.2913 + UPDATE_REG(0x200, IE); 1.2914 + if ((IME & 1) && (IF & IE) && armIrqEnable) 1.2915 + { 1.2916 + CPU_BREAK_LOOP_2; 1.2917 + } 1.2918 + break; 1.2919 + case 0x202: 1.2920 + IF ^= (value & IF); 1.2921 + UPDATE_REG(0x202, IF); 1.2922 + break; 1.2923 + case 0x204: 1.2924 + { 1.2925 + int i; 1.2926 + memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3]; 1.2927 + 1.2928 + if (!speedHack) 1.2929 + { 1.2930 + memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 7]; 1.2931 + memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 1.2932 + gamepakWaitState0[(value >> 2) & 7]; 1.2933 + 1.2934 + memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 7]; 1.2935 + memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 1.2936 + gamepakWaitState1[(value >> 5) & 7]; 1.2937 + 1.2938 + memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 7]; 1.2939 + memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 1.2940 + gamepakWaitState2[(value >> 8) & 7]; 1.2941 + } 1.2942 + else 1.2943 + { 1.2944 + memoryWait[0x08] = memoryWait[0x09] = 4; 1.2945 + memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 2; 1.2946 + 1.2947 + memoryWait[0x0a] = memoryWait[0x0b] = 4; 1.2948 + memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 4; 1.2949 + 1.2950 + memoryWait[0x0c] = memoryWait[0x0d] = 4; 1.2951 + memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 8; 1.2952 + } 1.2953 + for (i = 0; i < 16; i++) 1.2954 + { 1.2955 + memoryWaitFetch32[i] = memoryWait32[i] = memoryWait[i] * 1.2956 + (memory32[i] ? 1 : 2); 1.2957 + memoryWaitFetch[i] = memoryWait[i]; 1.2958 + } 1.2959 + memoryWaitFetch32[3] += 1; 1.2960 + memoryWaitFetch32[2] += 3; 1.2961 + 1.2962 + prefetchActive = false; 1.2963 + prefetchApplies = false; 1.2964 + if (value & 0x4000) 1.2965 + { 1.2966 + for (i = 8; i < 16; i++) 1.2967 + { 1.2968 + memoryWaitFetch32[i] = 2 * cpuMemoryWait[i]; 1.2969 + memoryWaitFetch[i] = cpuMemoryWait[i]; 1.2970 + } 1.2971 + if (((value & 3) == 3)) 1.2972 + { 1.2973 + if (!memLagTempEnabled) 1.2974 + { 1.2975 + memoryWaitFetch[8]--; // hack to prevent inaccurately extreme lag at some points of many games (possibly 1.2976 + // from no pre-fetch emulation) 1.2977 + /// FIXME: how correct is this? Should it set the fetch to 0 or change fetch32 or 1.2978 + // anything else? 1.2979 + 1.2980 + prefetchActive = true; 1.2981 + } 1.2982 + prefetchApplies = true; 1.2983 + } 1.2984 + } 1.2985 + //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600); 1.2986 + //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600); 1.2987 + prefetchPrevActive = prefetchActive; 1.2988 + 1.2989 + UPDATE_REG(0x204, value); 1.2990 + break; 1.2991 + } 1.2992 + case 0x208: 1.2993 + IME = value & 1; 1.2994 + UPDATE_REG(0x208, IME); 1.2995 + if ((IME & 1) && (IF & IE) && armIrqEnable) 1.2996 + { 1.2997 + CPU_BREAK_LOOP_2; 1.2998 + } 1.2999 + break; 1.3000 + case 0x300: 1.3001 + if (value != 0) 1.3002 + value &= 0xFFFE; 1.3003 + UPDATE_REG(0x300, value); 1.3004 + break; 1.3005 + default: 1.3006 + UPDATE_REG(address & 0x3FE, value); 1.3007 + break; 1.3008 + } 1.3009 +} 1.3010 + 1.3011 +void CPUWriteHalfWordWrapped(u32 address, u16 value) 1.3012 +{ 1.3013 +#ifdef GBA_LOGGING 1.3014 + if (address & 1) 1.3015 + { 1.3016 + if (systemVerbose & VERBOSE_UNALIGNED_MEMORY) 1.3017 + { 1.3018 + log("Unaligned halfword write: %04x to %08x from %08x\n", 1.3019 + value, 1.3020 + address, 1.3021 + armMode ? armNextPC - 4 : armNextPC - 2); 1.3022 + } 1.3023 + } 1.3024 +#endif 1.3025 + 1.3026 + switch (address >> 24) 1.3027 + { 1.3028 + case 2: 1.3029 +#ifdef SDL 1.3030 + if (*((u16 *)&freezeWorkRAM[address & 0x3FFFE])) 1.3031 + cheatsWriteHalfWord((u16 *)&workRAM[address & 0x3FFFE], 1.3032 + value, 1.3033 + *((u16 *)&freezeWorkRAM[address & 0x3FFFE])); 1.3034 + else 1.3035 +#endif 1.3036 + WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]), value); 1.3037 + break; 1.3038 + case 3: 1.3039 +#ifdef SDL 1.3040 + if (*((u16 *)&freezeInternalRAM[address & 0x7ffe])) 1.3041 + cheatsWriteHalfWord((u16 *)&internalRAM[address & 0x7ffe], 1.3042 + value, 1.3043 + *((u16 *)&freezeInternalRAM[address & 0x7ffe])); 1.3044 + else 1.3045 +#endif 1.3046 + WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value); 1.3047 + break; 1.3048 + case 4: 1.3049 + CPUUpdateRegister(address & 0x3fe, value); 1.3050 + break; 1.3051 + case 5: 1.3052 + WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value); 1.3053 + break; 1.3054 + case 6: 1.3055 + if (address & 0x10000) 1.3056 + WRITE16LE(((u16 *)&vram[address & 0x17ffe]), value); 1.3057 + else 1.3058 + WRITE16LE(((u16 *)&vram[address & 0x1fffe]), value); 1.3059 + break; 1.3060 + case 7: 1.3061 + WRITE16LE(((u16 *)&oam[address & 0x3fe]), value); 1.3062 + break; 1.3063 + case 8: 1.3064 + case 9: 1.3065 + if (address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) 1.3066 + { 1.3067 + if (!rtcWrite(address, value)) 1.3068 + goto unwritable; 1.3069 + } 1.3070 + else if (!agbPrintWrite(address, value)) 1.3071 + goto unwritable; 1.3072 + break; 1.3073 + case 13: 1.3074 + if (cpuEEPROMEnabled) 1.3075 + { 1.3076 + eepromWrite(address, (u8)(value & 0xFF)); 1.3077 + break; 1.3078 + } 1.3079 + goto unwritable; 1.3080 + case 14: 1.3081 + if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled) 1.3082 + { 1.3083 + (*cpuSaveGameFunc)(address, (u8)(value & 0xFF)); 1.3084 + break; 1.3085 + } 1.3086 + goto unwritable; 1.3087 + default: 1.3088 +unwritable: 1.3089 +#ifdef GBA_LOGGING 1.3090 + if (systemVerbose & VERBOSE_ILLEGAL_WRITE) 1.3091 + { 1.3092 + log("Illegal halfword write: %04x to %08x from %08x\n", 1.3093 + value, 1.3094 + address, 1.3095 + armMode ? armNextPC - 4 : armNextPC - 2); 1.3096 + } 1.3097 +#endif 1.3098 + break; 1.3099 + } 1.3100 +} 1.3101 + 1.3102 +void CPUWriteHalfWord(u32 address, u16 value) 1.3103 +{ 1.3104 + CPUWriteHalfWordWrapped(address, value); 1.3105 + CallRegisteredLuaMemHook(address, 2, value, LUAMEMHOOK_WRITE); 1.3106 +} 1.3107 + 1.3108 +void CPUWriteByteWrapped(u32 address, u8 b) 1.3109 +{ 1.3110 + switch (address >> 24) 1.3111 + { 1.3112 + case 2: 1.3113 +#ifdef SDL 1.3114 + if (freezeWorkRAM[address & 0x3FFFF]) 1.3115 + cheatsWriteByte(&workRAM[address & 0x3FFFF], b); 1.3116 + else 1.3117 +#endif 1.3118 + workRAM[address & 0x3FFFF] = b; 1.3119 + break; 1.3120 + case 3: 1.3121 +#ifdef SDL 1.3122 + if (freezeInternalRAM[address & 0x7fff]) 1.3123 + cheatsWriteByte(&internalRAM[address & 0x7fff], b); 1.3124 + else 1.3125 +#endif 1.3126 + internalRAM[address & 0x7fff] = b; 1.3127 + break; 1.3128 + case 4: 1.3129 + switch (address & 0x3FF) 1.3130 + { 1.3131 + case 0x301: 1.3132 + if (b == 0x80) 1.3133 + stopState = true; 1.3134 + holdState = 1; 1.3135 + holdType = -1; 1.3136 + break; 1.3137 + case 0x60: 1.3138 + case 0x61: 1.3139 + case 0x62: 1.3140 + case 0x63: 1.3141 + case 0x64: 1.3142 + case 0x65: 1.3143 + case 0x68: 1.3144 + case 0x69: 1.3145 + case 0x6c: 1.3146 + case 0x6d: 1.3147 + case 0x70: 1.3148 + case 0x71: 1.3149 + case 0x72: 1.3150 + case 0x73: 1.3151 + case 0x74: 1.3152 + case 0x75: 1.3153 + case 0x78: 1.3154 + case 0x79: 1.3155 + case 0x7c: 1.3156 + case 0x7d: 1.3157 + case 0x80: 1.3158 + case 0x81: 1.3159 + case 0x84: 1.3160 + case 0x85: 1.3161 + case 0x90: 1.3162 + case 0x91: 1.3163 + case 0x92: 1.3164 + case 0x93: 1.3165 + case 0x94: 1.3166 + case 0x95: 1.3167 + case 0x96: 1.3168 + case 0x97: 1.3169 + case 0x98: 1.3170 + case 0x99: 1.3171 + case 0x9a: 1.3172 + case 0x9b: 1.3173 + case 0x9c: 1.3174 + case 0x9d: 1.3175 + case 0x9e: 1.3176 + case 0x9f: 1.3177 + soundEvent(address & 0xFF, b); 1.3178 + break; 1.3179 + default: 1.3180 + // if(address & 1) { 1.3181 + // CPUWriteHalfWord(address-1, (CPUReadHalfWord(address-1)&0x00FF)|((int)b<<8)); 1.3182 + // } else 1.3183 + if (address & 1) 1.3184 + CPUUpdateRegister(address & 0x3fe, 1.3185 + ((READ16LE(((u16 *)&ioMem[address & 0x3fe]))) 1.3186 + & 0x00FF) | 1.3187 + b << 8); 1.3188 + else 1.3189 + CPUUpdateRegister(address & 0x3fe, 1.3190 + ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b)); 1.3191 + } 1.3192 + break; 1.3193 + case 5: 1.3194 + // no need to switch 1.3195 + *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b; 1.3196 + break; 1.3197 + case 6: 1.3198 + // no need to switch 1.3199 + if (address & 0x10000) 1.3200 + *((u16 *)&vram[address & 0x17FFE]) = (b << 8) | b; 1.3201 + else 1.3202 + *((u16 *)&vram[address & 0x1FFFE]) = (b << 8) | b; 1.3203 + break; 1.3204 + case 7: 1.3205 + // no need to switch 1.3206 + *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b; 1.3207 + break; 1.3208 + case 13: 1.3209 + if (cpuEEPROMEnabled) 1.3210 + { 1.3211 + eepromWrite(address, b); 1.3212 + break; 1.3213 + } 1.3214 + goto unwritable; 1.3215 + case 14: 1.3216 + if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled) 1.3217 + { 1.3218 + (*cpuSaveGameFunc)(address, b); 1.3219 + break; 1.3220 + } 1.3221 + // default 1.3222 + default: 1.3223 +unwritable: 1.3224 +#ifdef GBA_LOGGING 1.3225 + if (systemVerbose & VERBOSE_ILLEGAL_WRITE) 1.3226 + { 1.3227 + log("Illegal byte write: %02x to %08x from %08x\n", 1.3228 + b, 1.3229 + address, 1.3230 + armMode ? armNextPC - 4 : armNextPC - 2); 1.3231 + } 1.3232 +#endif 1.3233 + break; 1.3234 + } 1.3235 +} 1.3236 + 1.3237 +void CPUWriteByte(u32 address, u8 b) 1.3238 +{ 1.3239 + CPUWriteByteWrapped(address, b); 1.3240 + CallRegisteredLuaMemHook(address, 1, b, LUAMEMHOOK_WRITE); 1.3241 +} 1.3242 + 1.3243 +bool CPULoadBios(const char *biosFileName, bool useBiosFile) 1.3244 +{ 1.3245 + useBios = false; 1.3246 + if (useBiosFile) 1.3247 + { 1.3248 + useBios = utilLoadBIOS(bios, biosFileName, 4); 1.3249 + if (!useBios) 1.3250 + { 1.3251 + systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid GBA BIOS file")); 1.3252 + } 1.3253 + } 1.3254 + 1.3255 + if (!useBios) 1.3256 + { 1.3257 + // load internal BIOS 1.3258 + memcpy(bios, myROM, sizeof(myROM)); 1.3259 + } 1.3260 + 1.3261 + return useBios; 1.3262 +} 1.3263 + 1.3264 +void CPUInit() 1.3265 +{ 1.3266 +#ifdef WORDS_BIGENDIAN 1.3267 + if (!cpuBiosSwapped) 1.3268 + { 1.3269 + for (unsigned int i = 0; i < sizeof(myROM) / 4; i++) 1.3270 + { 1.3271 + WRITE32LE(&myROM[i], myROM[i]); 1.3272 + } 1.3273 + cpuBiosSwapped = true; 1.3274 + } 1.3275 +#endif 1.3276 + gbaSaveType = 0; 1.3277 + eepromInUse = 0; 1.3278 + saveType = 0; 1.3279 + 1.3280 + if (!useBios) 1.3281 + { 1.3282 + // load internal BIOS 1.3283 + memcpy(bios, myROM, sizeof(myROM)); 1.3284 + } 1.3285 + 1.3286 + biosProtected[0] = 0x00; 1.3287 + biosProtected[1] = 0xf0; 1.3288 + biosProtected[2] = 0x29; 1.3289 + biosProtected[3] = 0xe1; 1.3290 + 1.3291 + int i = 0; 1.3292 + for (i = 0; i < 256; i++) 1.3293 + { 1.3294 + int cpuBitSetCount = 0; 1.3295 + int j; 1.3296 + for (j = 0; j < 8; j++) 1.3297 + if (i & (1 << j)) 1.3298 + cpuBitSetCount++; 1.3299 + cpuBitsSet[i] = cpuBitSetCount; 1.3300 + 1.3301 + for (j = 0; j < 8; j++) 1.3302 + if (i & (1 << j)) 1.3303 + break; 1.3304 + cpuLowestBitSet[i] = j; 1.3305 + } 1.3306 + 1.3307 + for (i = 0; i < 0x400; i++) 1.3308 + ioReadable[i] = true; 1.3309 + for (i = 0x10; i < 0x48; i++) 1.3310 + ioReadable[i] = false; 1.3311 + for (i = 0x4c; i < 0x50; i++) 1.3312 + ioReadable[i] = false; 1.3313 + for (i = 0x54; i < 0x60; i++) 1.3314 + ioReadable[i] = false; 1.3315 + for (i = 0x8c; i < 0x90; i++) 1.3316 + ioReadable[i] = false; 1.3317 + for (i = 0xa0; i < 0xb8; i++) 1.3318 + ioReadable[i] = false; 1.3319 + for (i = 0xbc; i < 0xc4; i++) 1.3320 + ioReadable[i] = false; 1.3321 + for (i = 0xc8; i < 0xd0; i++) 1.3322 + ioReadable[i] = false; 1.3323 + for (i = 0xd4; i < 0xdc; i++) 1.3324 + ioReadable[i] = false; 1.3325 + for (i = 0xe0; i < 0x100; i++) 1.3326 + ioReadable[i] = false; 1.3327 + for (i = 0x110; i < 0x120; i++) 1.3328 + ioReadable[i] = false; 1.3329 + for (i = 0x12c; i < 0x130; i++) 1.3330 + ioReadable[i] = false; 1.3331 + for (i = 0x138; i < 0x140; i++) 1.3332 + ioReadable[i] = false; 1.3333 + for (i = 0x144; i < 0x150; i++) 1.3334 + ioReadable[i] = false; 1.3335 + for (i = 0x15c; i < 0x200; i++) 1.3336 + ioReadable[i] = false; 1.3337 + for (i = 0x20c; i < 0x300; i++) 1.3338 + ioReadable[i] = false; 1.3339 + for (i = 0x304; i < 0x400; i++) 1.3340 + ioReadable[i] = false; 1.3341 + 1.3342 + *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA 1.3343 + *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR 1.3344 + 1.3345 + { 1.3346 + int32 origMemoryWaitFetch[16] = { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; 1.3347 + int32 origMemoryWaitFetch32[16] = { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 }; 1.3348 + memcpy(memoryWaitFetch, origMemoryWaitFetch, 16 * sizeof(int32)); 1.3349 + memcpy(memoryWaitFetch32, origMemoryWaitFetch32, 16 * sizeof(int32)); 1.3350 + } 1.3351 +} 1.3352 + 1.3353 +void CPUReset(bool userReset) 1.3354 +{ 1.3355 + // movie must be closed while opening/creating a movie 1.3356 + if (userReset && VBAMovieRecording()) 1.3357 + { 1.3358 + VBAMovieSignalReset(); 1.3359 + return; 1.3360 + } 1.3361 + 1.3362 + if (!VBAMovieActive()) 1.3363 + { 1.3364 + GBASystemCounters.frameCount = 0; 1.3365 + GBASystemCounters.lagCount = 0; 1.3366 + GBASystemCounters.extraCount = 0; 1.3367 + GBASystemCounters.lagged = true; 1.3368 + GBASystemCounters.laggedLast = true; 1.3369 + } 1.3370 + 1.3371 + if (gbaSaveType == 0) 1.3372 + { 1.3373 + if (eepromInUse) 1.3374 + gbaSaveType = 3; 1.3375 + else 1.3376 + switch (saveType) 1.3377 + { 1.3378 + case 1: 1.3379 + gbaSaveType = 1; 1.3380 + break; 1.3381 + case 2: 1.3382 + gbaSaveType = 2; 1.3383 + break; 1.3384 + } 1.3385 + } 1.3386 + 1.3387 + rtcReset(); 1.3388 + // clean registers 1.3389 + memset(®[0], 0, sizeof(reg)); 1.3390 + // clean OAM 1.3391 + memset(oam, 0, 0x400); 1.3392 + // clean palette 1.3393 + memset(paletteRAM, 0, 0x400); 1.3394 + // clean picture 1.3395 + memset(pix, 0, 4 * 241 * 162); 1.3396 + // clean vram 1.3397 + memset(vram, 0, 0x20000); 1.3398 + // clean io memory 1.3399 + memset(ioMem, 0, 0x400); 1.3400 + // clean RAM 1.3401 + memset(internalRAM, 0, 0x8000); /// FIXME: is it unsafe to erase ALL of this? Even the init code doesn't. 1.3402 + memset(workRAM, 0, 0x40000); /// ditto 1.3403 + 1.3404 + DISPCNT = 0x0080; 1.3405 + DISPSTAT = 0x0000; 1.3406 + VCOUNT = 0x0000; 1.3407 + BG0CNT = 0x0000; 1.3408 + BG1CNT = 0x0000; 1.3409 + BG2CNT = 0x0000; 1.3410 + BG3CNT = 0x0000; 1.3411 + BG0HOFS = 0x0000; 1.3412 + BG0VOFS = 0x0000; 1.3413 + BG1HOFS = 0x0000; 1.3414 + BG1VOFS = 0x0000; 1.3415 + BG2HOFS = 0x0000; 1.3416 + BG2VOFS = 0x0000; 1.3417 + BG3HOFS = 0x0000; 1.3418 + BG3VOFS = 0x0000; 1.3419 + BG2PA = 0x0100; 1.3420 + BG2PB = 0x0000; 1.3421 + BG2PC = 0x0000; 1.3422 + BG2PD = 0x0100; 1.3423 + BG2X_L = 0x0000; 1.3424 + BG2X_H = 0x0000; 1.3425 + BG2Y_L = 0x0000; 1.3426 + BG2Y_H = 0x0000; 1.3427 + BG3PA = 0x0100; 1.3428 + BG3PB = 0x0000; 1.3429 + BG3PC = 0x0000; 1.3430 + BG3PD = 0x0100; 1.3431 + BG3X_L = 0x0000; 1.3432 + BG3X_H = 0x0000; 1.3433 + BG3Y_L = 0x0000; 1.3434 + BG3Y_H = 0x0000; 1.3435 + WIN0H = 0x0000; 1.3436 + WIN1H = 0x0000; 1.3437 + WIN0V = 0x0000; 1.3438 + WIN1V = 0x0000; 1.3439 + WININ = 0x0000; 1.3440 + WINOUT = 0x0000; 1.3441 + MOSAIC = 0x0000; 1.3442 + BLDMOD = 0x0000; 1.3443 + COLEV = 0x0000; 1.3444 + COLY = 0x0000; 1.3445 + DM0SAD_L = 0x0000; 1.3446 + DM0SAD_H = 0x0000; 1.3447 + DM0DAD_L = 0x0000; 1.3448 + DM0DAD_H = 0x0000; 1.3449 + DM0CNT_L = 0x0000; 1.3450 + DM0CNT_H = 0x0000; 1.3451 + DM1SAD_L = 0x0000; 1.3452 + DM1SAD_H = 0x0000; 1.3453 + DM1DAD_L = 0x0000; 1.3454 + DM1DAD_H = 0x0000; 1.3455 + DM1CNT_L = 0x0000; 1.3456 + DM1CNT_H = 0x0000; 1.3457 + DM2SAD_L = 0x0000; 1.3458 + DM2SAD_H = 0x0000; 1.3459 + DM2DAD_L = 0x0000; 1.3460 + DM2DAD_H = 0x0000; 1.3461 + DM2CNT_L = 0x0000; 1.3462 + DM2CNT_H = 0x0000; 1.3463 + DM3SAD_L = 0x0000; 1.3464 + DM3SAD_H = 0x0000; 1.3465 + DM3DAD_L = 0x0000; 1.3466 + DM3DAD_H = 0x0000; 1.3467 + DM3CNT_L = 0x0000; 1.3468 + DM3CNT_H = 0x0000; 1.3469 + TM0D = 0x0000; 1.3470 + TM0CNT = 0x0000; 1.3471 + TM1D = 0x0000; 1.3472 + TM1CNT = 0x0000; 1.3473 + TM2D = 0x0000; 1.3474 + TM2CNT = 0x0000; 1.3475 + TM3D = 0x0000; 1.3476 + TM3CNT = 0x0000; 1.3477 + P1 = 0x03FF; 1.3478 + IE = 0x0000; 1.3479 + IF = 0x0000; 1.3480 + IME = 0x0000; 1.3481 + 1.3482 + armMode = 0x1F; 1.3483 + 1.3484 + if (cpuIsMultiBoot) 1.3485 + { 1.3486 + reg[13].I = 0x03007F00; 1.3487 + reg[15].I = 0x02000000; 1.3488 + reg[16].I = 0x00000000; 1.3489 + reg[R13_IRQ].I = 0x03007FA0; 1.3490 + reg[R13_SVC].I = 0x03007FE0; 1.3491 + armIrqEnable = true; 1.3492 + } 1.3493 + else 1.3494 + { 1.3495 + if (useBios && !skipBios) 1.3496 + { 1.3497 + reg[15].I = 0x00000000; 1.3498 + armMode = 0x13; 1.3499 + armIrqEnable = false; 1.3500 + } 1.3501 + else 1.3502 + { 1.3503 + reg[13].I = 0x03007F00; 1.3504 + reg[15].I = 0x08000000; 1.3505 + reg[16].I = 0x00000000; 1.3506 + reg[R13_IRQ].I = 0x03007FA0; 1.3507 + reg[R13_SVC].I = 0x03007FE0; 1.3508 + armIrqEnable = true; 1.3509 + } 1.3510 + } 1.3511 + armState = true; 1.3512 + C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; 1.3513 + UPDATE_REG(0x00, DISPCNT); 1.3514 + UPDATE_REG(0x20, BG2PA); 1.3515 + UPDATE_REG(0x26, BG2PD); 1.3516 + UPDATE_REG(0x30, BG3PA); 1.3517 + UPDATE_REG(0x36, BG3PD); 1.3518 + UPDATE_REG(0x130, P1); 1.3519 + UPDATE_REG(0x88, 0x200); 1.3520 + 1.3521 + // disable FIQ 1.3522 + reg[16].I |= 0x40; 1.3523 + CPUUpdateCPSR(); 1.3524 + 1.3525 + armNextPC = reg[15].I; 1.3526 + reg[15].I += 4; 1.3527 + 1.3528 + // reset internal state 1.3529 + holdState = false; 1.3530 + holdType = 0; 1.3531 + 1.3532 + biosProtected[0] = 0x00; 1.3533 + biosProtected[1] = 0xf0; 1.3534 + biosProtected[2] = 0x29; 1.3535 + biosProtected[3] = 0xe1; 1.3536 + 1.3537 + BIOS_RegisterRamReset(); 1.3538 + 1.3539 + lcdTicks = 960; 1.3540 + timer0On = false; 1.3541 + timer0Ticks = 0; 1.3542 + timer0Reload = 0; 1.3543 + timer0ClockReload = 0; 1.3544 + timer1On = false; 1.3545 + timer1Ticks = 0; 1.3546 + timer1Reload = 0; 1.3547 + timer1ClockReload = 0; 1.3548 + timer2On = false; 1.3549 + timer2Ticks = 0; 1.3550 + timer2Reload = 0; 1.3551 + timer2ClockReload = 0; 1.3552 + timer3On = false; 1.3553 + timer3Ticks = 0; 1.3554 + timer3Reload = 0; 1.3555 + timer3ClockReload = 0; 1.3556 + dma0Source = 0; 1.3557 + dma0Dest = 0; 1.3558 + dma1Source = 0; 1.3559 + dma1Dest = 0; 1.3560 + dma2Source = 0; 1.3561 + dma2Dest = 0; 1.3562 + dma3Source = 0; 1.3563 + dma3Dest = 0; 1.3564 + cpuSaveGameFunc = flashSaveDecide; 1.3565 + renderLine = mode0RenderLine; 1.3566 + fxOn = false; 1.3567 + windowOn = false; 1.3568 + frameSkipCount = 0; 1.3569 + saveType = 0; 1.3570 + layerEnable = DISPCNT & layerSettings; 1.3571 + 1.3572 + CPUUpdateRenderBuffers(true); 1.3573 + 1.3574 + for (int i = 0; i < 256; i++) 1.3575 + { 1.3576 + map[i].address = (u8 *)&dummyAddress; 1.3577 + map[i].mask = 0; 1.3578 + } 1.3579 + 1.3580 + map[0].address = bios; 1.3581 + map[0].mask = 0x3FFF; 1.3582 + map[2].address = workRAM; 1.3583 + map[2].mask = 0x3FFFF; 1.3584 + map[3].address = internalRAM; 1.3585 + map[3].mask = 0x7FFF; 1.3586 + map[4].address = ioMem; 1.3587 + map[4].mask = 0x3FF; 1.3588 + map[5].address = paletteRAM; 1.3589 + map[5].mask = 0x3FF; 1.3590 + map[6].address = vram; 1.3591 + map[6].mask = 0x1FFFF; 1.3592 + map[7].address = oam; 1.3593 + map[7].mask = 0x3FF; 1.3594 + map[8].address = rom; 1.3595 + map[8].mask = 0x1FFFFFF; 1.3596 + map[9].address = rom; 1.3597 + map[9].mask = 0x1FFFFFF; 1.3598 + map[10].address = rom; 1.3599 + map[10].mask = 0x1FFFFFF; 1.3600 + map[12].address = rom; 1.3601 + map[12].mask = 0x1FFFFFF; 1.3602 + map[14].address = flashSaveMemory; 1.3603 + map[14].mask = 0xFFFF; 1.3604 + 1.3605 + eepromReset(); 1.3606 + flashReset(); 1.3607 + 1.3608 + soundReset(); 1.3609 + 1.3610 + CPUUpdateWindow0(); 1.3611 + CPUUpdateWindow1(); 1.3612 + 1.3613 + // make sure registers are correctly initialized if not using BIOS 1.3614 + if (!useBios) 1.3615 + { 1.3616 + if (cpuIsMultiBoot) 1.3617 + BIOS_RegisterRamReset(0xfe); 1.3618 + else 1.3619 + BIOS_RegisterRamReset(0xff); 1.3620 + } 1.3621 + else 1.3622 + { 1.3623 + if (cpuIsMultiBoot) 1.3624 + BIOS_RegisterRamReset(0xfe); 1.3625 + } 1.3626 + 1.3627 + switch (cpuSaveType) 1.3628 + { 1.3629 + case 0: // automatic 1.3630 + cpuSramEnabled = true; 1.3631 + cpuFlashEnabled = true; 1.3632 + cpuEEPROMEnabled = true; 1.3633 + cpuEEPROMSensorEnabled = false; 1.3634 + break; 1.3635 + case 1: // EEPROM 1.3636 + cpuSramEnabled = false; 1.3637 + cpuFlashEnabled = false; 1.3638 + cpuEEPROMEnabled = true; 1.3639 + cpuEEPROMSensorEnabled = false; 1.3640 + break; 1.3641 + case 2: // SRAM 1.3642 + cpuSramEnabled = true; 1.3643 + cpuFlashEnabled = false; 1.3644 + cpuEEPROMEnabled = false; 1.3645 + cpuEEPROMSensorEnabled = false; 1.3646 + cpuSaveGameFunc = sramWrite; 1.3647 + break; 1.3648 + case 3: // FLASH 1.3649 + cpuSramEnabled = false; 1.3650 + cpuFlashEnabled = true; 1.3651 + cpuEEPROMEnabled = false; 1.3652 + cpuEEPROMSensorEnabled = false; 1.3653 + cpuSaveGameFunc = flashWrite; 1.3654 + break; 1.3655 + case 4: // EEPROM+Sensor 1.3656 + cpuSramEnabled = false; 1.3657 + cpuFlashEnabled = false; 1.3658 + cpuEEPROMEnabled = true; 1.3659 + cpuEEPROMSensorEnabled = true; 1.3660 + break; 1.3661 + case 5: // NONE 1.3662 + cpuSramEnabled = false; 1.3663 + cpuFlashEnabled = false; 1.3664 + cpuEEPROMEnabled = false; 1.3665 + cpuEEPROMSensorEnabled = false; 1.3666 + break; 1.3667 + } 1.3668 + 1.3669 + systemResetSensor(); 1.3670 + 1.3671 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 1.3672 + 1.3673 + gbaLastTime = systemGetClock(); 1.3674 + gbaFrameCount = 0; 1.3675 + 1.3676 + systemRefreshScreen(); 1.3677 +} 1.3678 + 1.3679 +void CPUInterrupt() 1.3680 +{ 1.3681 + u32 PC = reg[15].I; 1.3682 + bool savedState = armState; 1.3683 + CPUSwitchMode(0x12, true, false); 1.3684 + reg[14].I = PC; 1.3685 + if (!savedState) 1.3686 + reg[14].I += 2; 1.3687 + reg[15].I = 0x18; 1.3688 + armState = true; 1.3689 + armIrqEnable = false; 1.3690 + 1.3691 + armNextPC = reg[15].I; 1.3692 + reg[15].I += 4; 1.3693 + 1.3694 + // if(!holdState) 1.3695 + biosProtected[0] = 0x02; 1.3696 + biosProtected[1] = 0xc0; 1.3697 + biosProtected[2] = 0x5e; 1.3698 + biosProtected[3] = 0xe5; 1.3699 +} 1.3700 + 1.3701 +void TogglePrefetchHack() 1.3702 +{ 1.3703 + memLagTempEnabled = !memLagTempEnabled; 1.3704 + 1.3705 + if (emulating) 1.3706 + { 1.3707 + extern bool8 prefetchActive, prefetchPrevActive, prefetchApplies; 1.3708 + if (prefetchApplies && prefetchActive == memLagTempEnabled) 1.3709 + { 1.3710 + prefetchActive = !prefetchActive; 1.3711 + //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600); 1.3712 + //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600); 1.3713 + extern int32 memoryWaitFetch [16]; 1.3714 + if (prefetchActive) 1.3715 + memoryWaitFetch[8]--; 1.3716 + else 1.3717 + memoryWaitFetch[8]++; 1.3718 + prefetchPrevActive = prefetchActive; 1.3719 + } 1.3720 + } 1.3721 +} 1.3722 + 1.3723 +void SetPrefetchHack(bool set) 1.3724 +{ 1.3725 + if ((bool)memLagTempEnabled == set) 1.3726 + TogglePrefetchHack(); 1.3727 +} 1.3728 + 1.3729 +#ifdef SDL 1.3730 +void log(const char *defaultMsg, ...) 1.3731 +{ 1.3732 + char buffer[2048]; 1.3733 + va_list valist; 1.3734 + 1.3735 + va_start(valist, defaultMsg); 1.3736 + vsprintf(buffer, defaultMsg, valist); 1.3737 + 1.3738 + if (out == NULL) 1.3739 + { 1.3740 + out = fopen("trace.log", "w"); 1.3741 + } 1.3742 + 1.3743 + fputs(buffer, out); 1.3744 + 1.3745 + va_end(valist); 1.3746 +} 1.3747 + 1.3748 +#else 1.3749 +extern void winlog(const char *, ...); 1.3750 +#endif 1.3751 + 1.3752 +void CPULoop(int _ticks) 1.3753 +{ 1.3754 + int32 ticks = _ticks; 1.3755 + int32 clockTicks; 1.3756 + int32 cpuLoopTicks = 0; 1.3757 + int32 timerOverflow = 0; 1.3758 + // variables used by the CPU core 1.3759 + 1.3760 + extCpuLoopTicks = &cpuLoopTicks; 1.3761 + extClockTicks = &clockTicks; 1.3762 + extTicks = &ticks; 1.3763 + 1.3764 + cpuLoopTicks = CPUUpdateTicks(); 1.3765 + if (cpuLoopTicks > ticks) 1.3766 + { 1.3767 + cpuLoopTicks = ticks; 1.3768 + cpuSavedTicks = ticks; 1.3769 + } 1.3770 + 1.3771 + if (intState) 1.3772 + { 1.3773 + cpuLoopTicks = 5; 1.3774 + cpuSavedTicks = 5; 1.3775 + } 1.3776 + 1.3777 + if (newFrame) 1.3778 + { 1.3779 + extern void VBAOnExitingFrameBoundary(); 1.3780 + VBAOnExitingFrameBoundary(); 1.3781 + 1.3782 + // update joystick information 1.3783 + systemReadJoypads(); 1.3784 + 1.3785 + u32 joy = systemGetJoypad(0, cpuEEPROMSensorEnabled); 1.3786 + 1.3787 +// if (cpuEEPROMSensorEnabled) 1.3788 +// systemUpdateMotionSensor(0); 1.3789 + 1.3790 + P1 = 0x03FF ^ (joy & 0x3FF); 1.3791 + UPDATE_REG(0x130, P1); 1.3792 + u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132])); 1.3793 + // this seems wrong, but there are cases where the game 1.3794 + // can enter the stop state without requesting an IRQ from 1.3795 + // the joypad. 1.3796 + if ((P1CNT & 0x4000) || stopState) 1.3797 + { 1.3798 + u16 p1 = (0x3FF ^ P1) & 0x3FF; 1.3799 + if (P1CNT & 0x8000) 1.3800 + { 1.3801 + if (p1 == (P1CNT & 0x3FF)) 1.3802 + { 1.3803 + IF |= 0x1000; 1.3804 + UPDATE_REG(0x202, IF); 1.3805 + } 1.3806 + } 1.3807 + else 1.3808 + { 1.3809 + if (p1 & P1CNT) 1.3810 + { 1.3811 + IF |= 0x1000; 1.3812 + UPDATE_REG(0x202, IF); 1.3813 + } 1.3814 + } 1.3815 + } 1.3816 + 1.3817 + // HACK: some special "buttons" 1.3818 + extButtons = (joy >> 18); 1.3819 + speedup = (extButtons & 1) != 0; 1.3820 + 1.3821 + VBAMovieResetIfRequested(); 1.3822 + 1.3823 + CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); 1.3824 + 1.3825 + newFrame = false; 1.3826 + } 1.3827 + 1.3828 + for (;; ) 1.3829 + { 1.3830 +#ifndef FINAL_VERSION 1.3831 + if (systemDebug) 1.3832 + { 1.3833 + if (systemDebug >= 10 && !holdState) 1.3834 + { 1.3835 + CPUUpdateCPSR(); 1.3836 + sprintf( 1.3837 + buffer, 1.3838 + "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x" 1.3839 + "R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", 1.3840 + reg[0].I, 1.3841 + reg[1].I, 1.3842 + reg[2].I, 1.3843 + reg[3].I, 1.3844 + reg[4].I, 1.3845 + reg[5].I, 1.3846 + reg[6].I, 1.3847 + reg[7].I, 1.3848 + reg[8].I, 1.3849 + reg[9].I, 1.3850 + reg[10].I, 1.3851 + reg[11].I, 1.3852 + reg[12].I, 1.3853 + reg[13].I, 1.3854 + reg[14].I, 1.3855 + reg[15].I, 1.3856 + reg[16].I, 1.3857 + reg[17].I); 1.3858 +#ifdef SDL 1.3859 + log(buffer); 1.3860 +#else 1.3861 + winlog(buffer); 1.3862 +#endif 1.3863 + } 1.3864 + else if (!holdState) 1.3865 + { 1.3866 + sprintf(buffer, "PC=%08x\n", armNextPC); 1.3867 +#ifdef SDL 1.3868 + log(buffer); 1.3869 +#else 1.3870 + winlog(buffer); 1.3871 +#endif 1.3872 + } 1.3873 + } 1.3874 +#endif 1.3875 + 1.3876 + if (!holdState) 1.3877 + { 1.3878 + if (armState) 1.3879 + { 1.3880 + CallRegisteredLuaMemHook(armNextPC, 4, CPUReadMemoryQuick(armNextPC), LUAMEMHOOK_EXEC); 1.3881 +#include "arm-new.h" 1.3882 + } 1.3883 + else 1.3884 + { 1.3885 + CallRegisteredLuaMemHook(armNextPC, 2, CPUReadHalfWordQuick(armNextPC), LUAMEMHOOK_EXEC); 1.3886 +#include "thumb.h" 1.3887 + } 1.3888 + } 1.3889 + else 1.3890 + { 1.3891 + clockTicks = lcdTicks; 1.3892 + 1.3893 + if (soundTicks < clockTicks) 1.3894 + clockTicks = soundTicks; 1.3895 + 1.3896 + if (timer0On && (timer0Ticks < clockTicks)) 1.3897 + { 1.3898 + clockTicks = timer0Ticks; 1.3899 + } 1.3900 + if (timer1On && (timer1Ticks < clockTicks)) 1.3901 + { 1.3902 + clockTicks = timer1Ticks; 1.3903 + } 1.3904 + if (timer2On && (timer2Ticks < clockTicks)) 1.3905 + { 1.3906 + clockTicks = timer2Ticks; 1.3907 + } 1.3908 + if (timer3On && (timer3Ticks < clockTicks)) 1.3909 + { 1.3910 + clockTicks = timer3Ticks; 1.3911 + } 1.3912 +#ifdef PROFILING 1.3913 + if (profilingTicksReload != 0) 1.3914 + { 1.3915 + if (profilingTicks < clockTicks) 1.3916 + { 1.3917 + clockTicks = profilingTicks; 1.3918 + } 1.3919 + } 1.3920 +#endif 1.3921 + } 1.3922 + 1.3923 + cpuLoopTicks -= clockTicks; 1.3924 + if ((cpuLoopTicks <= 0)) 1.3925 + { 1.3926 + if (cpuSavedTicks) 1.3927 + { 1.3928 + clockTicks = cpuSavedTicks; // + cpuLoopTicks; 1.3929 + } 1.3930 + cpuDmaTicksToUpdate = -cpuLoopTicks; 1.3931 + 1.3932 +updateLoop: 1.3933 + lcdTicks -= clockTicks; 1.3934 + 1.3935 + if (lcdTicks <= 0) 1.3936 + { 1.3937 + if (DISPSTAT & 1) // V-BLANK 1.3938 + { // if in V-Blank mode, keep computing... 1.3939 + if (DISPSTAT & 2) 1.3940 + { 1.3941 + lcdTicks += 960; 1.3942 + VCOUNT++; 1.3943 + UPDATE_REG(0x06, VCOUNT); 1.3944 + DISPSTAT &= 0xFFFD; 1.3945 + UPDATE_REG(0x04, DISPSTAT); 1.3946 + CPUCompareVCOUNT(); 1.3947 + } 1.3948 + else 1.3949 + { 1.3950 + lcdTicks += 272; 1.3951 + DISPSTAT |= 2; 1.3952 + UPDATE_REG(0x04, DISPSTAT); 1.3953 + if (DISPSTAT & 16) 1.3954 + { 1.3955 + IF |= 2; 1.3956 + UPDATE_REG(0x202, IF); 1.3957 + } 1.3958 + } 1.3959 + 1.3960 + if (VCOUNT >= 228) 1.3961 + { 1.3962 + DISPSTAT &= 0xFFFC; 1.3963 + UPDATE_REG(0x04, DISPSTAT); 1.3964 + VCOUNT = 0; 1.3965 + UPDATE_REG(0x06, VCOUNT); 1.3966 + CPUCompareVCOUNT(); 1.3967 + } 1.3968 + } 1.3969 + else 1.3970 + { 1.3971 + int framesToSkip = systemFramesToSkip(); 1.3972 + 1.3973 + if (DISPSTAT & 2) 1.3974 + { 1.3975 + // if in H-Blank, leave it and move to drawing mode 1.3976 + VCOUNT++; 1.3977 + UPDATE_REG(0x06, VCOUNT); 1.3978 + 1.3979 + lcdTicks += 960; 1.3980 + DISPSTAT &= 0xFFFD; 1.3981 + if (VCOUNT == 160) 1.3982 + { 1.3983 + DISPSTAT |= 1; 1.3984 + DISPSTAT &= 0xFFFD; 1.3985 + UPDATE_REG(0x04, DISPSTAT); 1.3986 + if (DISPSTAT & 0x0008) 1.3987 + { 1.3988 + IF |= 1; 1.3989 + UPDATE_REG(0x202, IF); 1.3990 + } 1.3991 + CPUCheckDMA(1, 0x0f); 1.3992 + 1.3993 + systemFrame(); 1.3994 + 1.3995 + ++gbaFrameCount; 1.3996 + u32 gbaCurrentTime = systemGetClock(); 1.3997 + if (gbaCurrentTime - gbaLastTime >= 1000) 1.3998 + { 1.3999 + systemShowSpeed(int(float(gbaFrameCount) * 100000 / (float(gbaCurrentTime - gbaLastTime) * 60) + .5f)); 1.4000 + gbaLastTime = gbaCurrentTime; 1.4001 + gbaFrameCount = 0; 1.4002 + } 1.4003 + 1.4004 + ++GBASystemCounters.frameCount; 1.4005 + if (GBASystemCounters.lagged) 1.4006 + { 1.4007 + ++GBASystemCounters.lagCount; 1.4008 + } 1.4009 + GBASystemCounters.laggedLast = GBASystemCounters.lagged; 1.4010 + GBASystemCounters.lagged = true; 1.4011 + 1.4012 + if (cheatsEnabled) 1.4013 + cheatsCheckKeys(P1 ^ 0x3FF, extButtons); 1.4014 + 1.4015 + extern void VBAOnEnteringFrameBoundary(); 1.4016 + VBAOnEnteringFrameBoundary(); 1.4017 + 1.4018 + newFrame = true; 1.4019 + 1.4020 + pauseAfterFrameAdvance = systemPauseOnFrame(); 1.4021 + 1.4022 + if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance) 1.4023 + { 1.4024 + systemRenderFrame(); 1.4025 + frameSkipCount = 0; 1.4026 + 1.4027 + bool capturePressed = (extButtons & 2) != 0; 1.4028 + if (capturePressed && !capturePrevious) 1.4029 + { 1.4030 + captureNumber = systemScreenCapture(captureNumber); 1.4031 + } 1.4032 + capturePrevious = capturePressed && !pauseAfterFrameAdvance; 1.4033 + } 1.4034 + else 1.4035 + { 1.4036 + ++frameSkipCount; 1.4037 + } 1.4038 + 1.4039 + if (pauseAfterFrameAdvance) 1.4040 + { 1.4041 + systemSetPause(true); 1.4042 + } 1.4043 + } 1.4044 + 1.4045 + UPDATE_REG(0x04, DISPSTAT); 1.4046 + CPUCompareVCOUNT(); 1.4047 + } 1.4048 + else 1.4049 + { 1.4050 + if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance) 1.4051 + { 1.4052 + (*renderLine)(); 1.4053 + 1.4054 + switch (systemColorDepth) 1.4055 + { 1.4056 + case 16: 1.4057 + { 1.4058 + u16 *dest = (u16 *)pix + 242 * (VCOUNT + 1); 1.4059 + for (int x = 0; x < 240; ) 1.4060 + { 1.4061 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4062 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4063 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4064 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4065 + 1.4066 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4067 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4068 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4069 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4070 + 1.4071 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4072 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4073 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4074 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4075 + 1.4076 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4077 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4078 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4079 + *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; 1.4080 + } 1.4081 + // for filters that read past the screen 1.4082 + *dest++ = 0; 1.4083 + break; 1.4084 + } 1.4085 + case 24: 1.4086 + { 1.4087 + u8 *dest = (u8 *)pix + 240 * VCOUNT * 3; 1.4088 + for (int x = 0; x < 240; ) 1.4089 + { 1.4090 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4091 + dest += 3; 1.4092 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4093 + dest += 3; 1.4094 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4095 + dest += 3; 1.4096 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4097 + dest += 3; 1.4098 + 1.4099 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4100 + dest += 3; 1.4101 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4102 + dest += 3; 1.4103 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4104 + dest += 3; 1.4105 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4106 + dest += 3; 1.4107 + 1.4108 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4109 + dest += 3; 1.4110 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4111 + dest += 3; 1.4112 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4113 + dest += 3; 1.4114 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4115 + dest += 3; 1.4116 + 1.4117 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4118 + dest += 3; 1.4119 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4120 + dest += 3; 1.4121 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4122 + dest += 3; 1.4123 + *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4124 + dest += 3; 1.4125 + } 1.4126 + break; 1.4127 + } 1.4128 + case 32: 1.4129 + { 1.4130 + u32 *dest = (u32 *)pix + 241 * (VCOUNT + 1); 1.4131 + for (int x = 0; x < 240; ) 1.4132 + { 1.4133 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4134 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4135 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4136 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4137 + 1.4138 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4139 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4140 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4141 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4142 + 1.4143 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4144 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4145 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4146 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4147 + 1.4148 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4149 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4150 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4151 + *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; 1.4152 + } 1.4153 + break; 1.4154 + } 1.4155 + } 1.4156 + } 1.4157 + // entering H-Blank 1.4158 + DISPSTAT |= 2; 1.4159 + UPDATE_REG(0x04, DISPSTAT); 1.4160 + lcdTicks += 272; 1.4161 + CPUCheckDMA(2, 0x0f); 1.4162 + if (DISPSTAT & 16) 1.4163 + { 1.4164 + IF |= 2; 1.4165 + UPDATE_REG(0x202, IF); 1.4166 + } 1.4167 + } 1.4168 + } 1.4169 + } 1.4170 + 1.4171 + if (!stopState) 1.4172 + { 1.4173 + if (timer0On) 1.4174 + { 1.4175 + if (timer0ClockReload == 1) 1.4176 + { 1.4177 + u32 tm0d = TM0D + clockTicks; 1.4178 + if (tm0d > 0xffff) 1.4179 + { 1.4180 + tm0d += timer0Reload; 1.4181 + timerOverflow |= 1; 1.4182 + soundTimerOverflow(0); 1.4183 + if (TM0CNT & 0x40) 1.4184 + { 1.4185 + IF |= 0x08; 1.4186 + UPDATE_REG(0x202, IF); 1.4187 + } 1.4188 + } 1.4189 + TM0D = tm0d & 0xFFFF; 1.4190 + timer0Ticks = 0x10000 - TM0D; 1.4191 + UPDATE_REG(0x100, TM0D); 1.4192 + } 1.4193 + else 1.4194 + { 1.4195 + timer0Ticks -= clockTicks; 1.4196 + if (timer0Ticks <= 0) 1.4197 + { 1.4198 + timer0Ticks += timer0ClockReload; 1.4199 + TM0D++; 1.4200 + if (TM0D == 0) 1.4201 + { 1.4202 + TM0D = timer0Reload; 1.4203 + timerOverflow |= 1; 1.4204 + soundTimerOverflow(0); 1.4205 + if (TM0CNT & 0x40) 1.4206 + { 1.4207 + IF |= 0x08; 1.4208 + UPDATE_REG(0x202, IF); 1.4209 + } 1.4210 + } 1.4211 + UPDATE_REG(0x100, TM0D); 1.4212 + } 1.4213 + } 1.4214 + } 1.4215 + 1.4216 + if (timer1On) 1.4217 + { 1.4218 + if (TM1CNT & 4) 1.4219 + { 1.4220 + if (timerOverflow & 1) 1.4221 + { 1.4222 + TM1D++; 1.4223 + if (TM1D == 0) 1.4224 + { 1.4225 + TM1D += timer1Reload; 1.4226 + timerOverflow |= 2; 1.4227 + soundTimerOverflow(1); 1.4228 + if (TM1CNT & 0x40) 1.4229 + { 1.4230 + IF |= 0x10; 1.4231 + UPDATE_REG(0x202, IF); 1.4232 + } 1.4233 + } 1.4234 + UPDATE_REG(0x104, TM1D); 1.4235 + } 1.4236 + } 1.4237 + else 1.4238 + { 1.4239 + if (timer1ClockReload == 1) 1.4240 + { 1.4241 + u32 tm1d = TM1D + clockTicks; 1.4242 + if (tm1d > 0xffff) 1.4243 + { 1.4244 + tm1d += timer1Reload; 1.4245 + timerOverflow |= 2; 1.4246 + soundTimerOverflow(1); 1.4247 + if (TM1CNT & 0x40) 1.4248 + { 1.4249 + IF |= 0x10; 1.4250 + UPDATE_REG(0x202, IF); 1.4251 + } 1.4252 + } 1.4253 + TM1D = tm1d & 0xFFFF; 1.4254 + timer1Ticks = 0x10000 - TM1D; 1.4255 + UPDATE_REG(0x104, TM1D); 1.4256 + } 1.4257 + else 1.4258 + { 1.4259 + timer1Ticks -= clockTicks; 1.4260 + if (timer1Ticks <= 0) 1.4261 + { 1.4262 + timer1Ticks += timer1ClockReload; 1.4263 + TM1D++; 1.4264 + 1.4265 + if (TM1D == 0) 1.4266 + { 1.4267 + TM1D = timer1Reload; 1.4268 + timerOverflow |= 2; 1.4269 + soundTimerOverflow(1); 1.4270 + if (TM1CNT & 0x40) 1.4271 + { 1.4272 + IF |= 0x10; 1.4273 + UPDATE_REG(0x202, IF); 1.4274 + } 1.4275 + } 1.4276 + UPDATE_REG(0x104, TM1D); 1.4277 + } 1.4278 + } 1.4279 + } 1.4280 + } 1.4281 + 1.4282 + if (timer2On) 1.4283 + { 1.4284 + if (TM2CNT & 4) 1.4285 + { 1.4286 + if (timerOverflow & 2) 1.4287 + { 1.4288 + TM2D++; 1.4289 + if (TM2D == 0) 1.4290 + { 1.4291 + TM2D += timer2Reload; 1.4292 + timerOverflow |= 4; 1.4293 + if (TM2CNT & 0x40) 1.4294 + { 1.4295 + IF |= 0x20; 1.4296 + UPDATE_REG(0x202, IF); 1.4297 + } 1.4298 + } 1.4299 + UPDATE_REG(0x108, TM2D); 1.4300 + } 1.4301 + } 1.4302 + else 1.4303 + { 1.4304 + if (timer2ClockReload == 1) 1.4305 + { 1.4306 + u32 tm2d = TM2D + clockTicks; 1.4307 + if (tm2d > 0xffff) 1.4308 + { 1.4309 + tm2d += timer2Reload; 1.4310 + timerOverflow |= 4; 1.4311 + if (TM2CNT & 0x40) 1.4312 + { 1.4313 + IF |= 0x20; 1.4314 + UPDATE_REG(0x202, IF); 1.4315 + } 1.4316 + } 1.4317 + TM2D = tm2d & 0xFFFF; 1.4318 + timer2Ticks = 0x10000 - TM2D; 1.4319 + UPDATE_REG(0x108, TM2D); 1.4320 + } 1.4321 + else 1.4322 + { 1.4323 + timer2Ticks -= clockTicks; 1.4324 + if (timer2Ticks <= 0) 1.4325 + { 1.4326 + timer2Ticks += timer2ClockReload; 1.4327 + TM2D++; 1.4328 + 1.4329 + if (TM2D == 0) 1.4330 + { 1.4331 + TM2D = timer2Reload; 1.4332 + timerOverflow |= 4; 1.4333 + if (TM2CNT & 0x40) 1.4334 + { 1.4335 + IF |= 0x20; 1.4336 + UPDATE_REG(0x202, IF); 1.4337 + } 1.4338 + } 1.4339 + UPDATE_REG(0x108, TM2D); 1.4340 + } 1.4341 + } 1.4342 + } 1.4343 + } 1.4344 + 1.4345 + if (timer3On) 1.4346 + { 1.4347 + if (TM3CNT & 4) 1.4348 + { 1.4349 + if (timerOverflow & 4) 1.4350 + { 1.4351 + TM3D++; 1.4352 + if (TM3D == 0) 1.4353 + { 1.4354 + TM3D += timer3Reload; 1.4355 + if (TM3CNT & 0x40) 1.4356 + { 1.4357 + IF |= 0x40; 1.4358 + UPDATE_REG(0x202, IF); 1.4359 + } 1.4360 + } 1.4361 + UPDATE_REG(0x10c, TM3D); 1.4362 + } 1.4363 + } 1.4364 + else 1.4365 + { 1.4366 + if (timer3ClockReload == 1) 1.4367 + { 1.4368 + u32 tm3d = TM3D + clockTicks; 1.4369 + if (tm3d > 0xffff) 1.4370 + { 1.4371 + tm3d += timer3Reload; 1.4372 + if (TM3CNT & 0x40) 1.4373 + { 1.4374 + IF |= 0x40; 1.4375 + UPDATE_REG(0x202, IF); 1.4376 + } 1.4377 + } 1.4378 + TM3D = tm3d & 0xFFFF; 1.4379 + timer3Ticks = 0x10000 - TM3D; 1.4380 + UPDATE_REG(0x10C, TM3D); 1.4381 + } 1.4382 + else 1.4383 + { 1.4384 + timer3Ticks -= clockTicks; 1.4385 + if (timer3Ticks <= 0) 1.4386 + { 1.4387 + timer3Ticks += timer3ClockReload; 1.4388 + TM3D++; 1.4389 + 1.4390 + if (TM3D == 0) 1.4391 + { 1.4392 + TM3D = timer3Reload; 1.4393 + if (TM3CNT & 0x40) 1.4394 + { 1.4395 + IF |= 0x40; 1.4396 + UPDATE_REG(0x202, IF); 1.4397 + } 1.4398 + } 1.4399 + UPDATE_REG(0x10C, TM3D); 1.4400 + } 1.4401 + } 1.4402 + } 1.4403 + } 1.4404 + } 1.4405 + // we shouldn't be doing sound in stop state, but we lose synchronization 1.4406 + // if sound is disabled, so in stop state, soundTick will just produce 1.4407 + // mute sound 1.4408 + soundTicks -= clockTicks; 1.4409 + if (soundTicks < 1) 1.4410 + { 1.4411 + soundTick(); 1.4412 + soundTicks += SOUND_CLOCK_TICKS; 1.4413 + } 1.4414 + timerOverflow = 0; 1.4415 + 1.4416 +#ifdef PROFILING 1.4417 + profilingTicks -= clockTicks; 1.4418 + if (profilingTicks <= 0) 1.4419 + { 1.4420 + profilingTicks += profilingTicksReload; 1.4421 + if (profilBuffer && profilSize) 1.4422 + { 1.4423 + u16 *b = (u16 *)profilBuffer; 1.4424 + int pc = ((reg[15].I - profilLowPC) * profilScale) / 0x10000; 1.4425 + if (pc >= 0 && pc < profilSize) 1.4426 + { 1.4427 + b[pc]++; 1.4428 + } 1.4429 + } 1.4430 + } 1.4431 +#endif 1.4432 + 1.4433 + ticks -= clockTicks; 1.4434 + cpuLoopTicks = CPUUpdateTicks(); 1.4435 + 1.4436 + // FIXME: it is too bad that it is still not determined whether the loop can be exited at this point 1.4437 + if (cpuDmaTicksToUpdate > 0) 1.4438 + { 1.4439 + clockTicks = cpuSavedTicks; 1.4440 + if (clockTicks > cpuDmaTicksToUpdate) 1.4441 + clockTicks = cpuDmaTicksToUpdate; 1.4442 + cpuDmaTicksToUpdate -= clockTicks; 1.4443 + if (cpuDmaTicksToUpdate < 0) 1.4444 + cpuDmaTicksToUpdate = 0; 1.4445 + goto updateLoop; // this is evil 1.4446 + } 1.4447 + 1.4448 + if (IF && (IME & 1) && armIrqEnable) 1.4449 + { 1.4450 + int res = IF & IE; 1.4451 + if (stopState) 1.4452 + res &= 0x3080; 1.4453 + if (res) 1.4454 + { 1.4455 + if (intState) 1.4456 + { 1.4457 + CPUInterrupt(); 1.4458 + intState = false; 1.4459 + if (holdState) 1.4460 + { 1.4461 + holdState = false; 1.4462 + stopState = false; 1.4463 + } 1.4464 + } 1.4465 + else 1.4466 + { 1.4467 + if (!holdState) 1.4468 + { 1.4469 + intState = true; 1.4470 + cpuLoopTicks = 5; 1.4471 + cpuSavedTicks = 5; 1.4472 + } 1.4473 + else 1.4474 + { 1.4475 + CPUInterrupt(); 1.4476 + if (holdState) 1.4477 + { 1.4478 + holdState = false; 1.4479 + stopState = false; 1.4480 + } 1.4481 + } 1.4482 + } 1.4483 + } 1.4484 + } 1.4485 + 1.4486 + if (useOldFrameTiming) 1.4487 + { 1.4488 + if (ticks <= 0) 1.4489 + { 1.4490 + newFrame = true; 1.4491 + break; 1.4492 + } 1.4493 + } 1.4494 + else if (newFrame) 1.4495 + { 1.4496 + // FIXME: it should be enough to use frameBoundary only if there were no need for supporting the old timing 1.4497 + // but is there still any GBA .vbm that uses the old timing? 1.4498 +/// extern void VBAOnEnteringFrameBoundary(); 1.4499 +/// VBAOnEnteringFrameBoundary(); 1.4500 + 1.4501 + break; 1.4502 + } 1.4503 + } 1.4504 + } 1.4505 +} 1.4506 + 1.4507 +struct EmulatedSystem GBASystem = 1.4508 +{ 1.4509 + // emuMain 1.4510 + CPULoop, 1.4511 + // emuReset 1.4512 + CPUReset, 1.4513 + // emuCleanUp 1.4514 + CPUCleanUp, 1.4515 + // emuReadBattery 1.4516 + CPUReadBatteryFile, 1.4517 + // emuWriteBattery 1.4518 + CPUWriteBatteryFile, 1.4519 + // emuReadBatteryFromStream 1.4520 + CPUReadBatteryFromStream, 1.4521 + // emuWriteBatteryToStream 1.4522 + CPUWriteBatteryToStream, 1.4523 + // emuReadState 1.4524 + CPUReadState, 1.4525 + // emuWriteState 1.4526 + CPUWriteState, 1.4527 + // emuReadStateFromStream 1.4528 + CPUReadStateFromStream, 1.4529 + // emuWriteStateToStream 1.4530 + CPUWriteStateToStream, 1.4531 + // emuReadMemState 1.4532 + CPUReadMemState, 1.4533 + // emuWriteMemState 1.4534 + CPUWriteMemState, 1.4535 + // emuWritePNG 1.4536 + CPUWritePNGFile, 1.4537 + // emuWriteBMP 1.4538 + CPUWriteBMPFile, 1.4539 + // emuUpdateCPSR 1.4540 + CPUUpdateCPSR, 1.4541 + // emuHasDebugger 1.4542 + true, 1.4543 + // emuCount 1.4544 +#ifdef FINAL_VERSION 1.4545 + 250000, 1.4546 +#else 1.4547 + 5000, 1.4548 +#endif 1.4549 +}; 1.4550 + 1.4551 +// is there a reason to use more than one set of counters? 1.4552 +EmulatedSystemCounters &GBASystemCounters = systemCounters; 1.4553 + 1.4554 +/* 1.4555 + EmulatedSystemCounters GBASystemCounters = 1.4556 + { 1.4557 + // frameCount 1.4558 + 0, 1.4559 + // lagCount 1.4560 + 0, 1.4561 + // lagged 1.4562 + true, 1.4563 + // laggedLast 1.4564 + true, 1.4565 + }; 1.4566 + */ 1.4567 + 1.4568 + 1.4569 +#undef CPU_BREAK_LOOP 1.4570 +#undef CPU_BREAK_LOOP2