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