rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: #include "../Port.h" rlm@1: #include "../NLS.h" rlm@1: #include "GBA.h" rlm@1: //#include "GBAGlobals.h" rlm@1: #include "GBACheats.h" // FIXME: SDL requires this included before "GBAinline.h" rlm@1: #include "GBAinline.h" rlm@1: #include "GBAGfx.h" rlm@1: #include "GBASound.h" rlm@1: #include "EEprom.h" rlm@1: #include "Flash.h" rlm@1: #include "Sram.h" rlm@1: #include "bios.h" rlm@1: #include "elf.h" rlm@1: #include "agbprint.h" rlm@1: #include "../common/unzip.h" rlm@1: #include "../common/Util.h" rlm@1: #include "../common/movie.h" rlm@1: #include "../common/vbalua.h" rlm@1: rlm@1: #ifdef PROFILING rlm@1: #include "../prof/prof.h" rlm@1: #endif rlm@1: rlm@1: #define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]), value) rlm@1: rlm@1: #ifdef __GNUC__ rlm@1: #define _stricmp strcasecmp rlm@1: #endif rlm@1: rlm@1: #define CPU_BREAK_LOOP \ rlm@1: cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \ rlm@1: *extCpuLoopTicks = *extClockTicks; rlm@1: rlm@1: #define CPU_BREAK_LOOP_2 \ rlm@1: cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \ rlm@1: *extCpuLoopTicks = *extClockTicks; \ rlm@1: *extTicks = *extClockTicks; rlm@1: rlm@1: int32 cpuDmaTicksToUpdate = 0; rlm@1: int32 cpuDmaCount = 0; rlm@1: bool8 cpuDmaHack = 0; rlm@1: u32 cpuDmaLast = 0; rlm@1: int32 dummyAddress = 0; rlm@1: rlm@1: int32 *extCpuLoopTicks = NULL; rlm@1: int32 *extClockTicks = NULL; rlm@1: int32 *extTicks = NULL; rlm@1: rlm@1: #if (defined(WIN32) && !defined(SDL)) rlm@1: HANDLE mapROM; // shared memory handles rlm@1: HANDLE mapWORKRAM; rlm@1: HANDLE mapBIOS; rlm@1: HANDLE mapIRAM; rlm@1: HANDLE mapPALETTERAM; rlm@1: HANDLE mapVRAM; rlm@1: HANDLE mapOAM; rlm@1: HANDLE mapPIX; rlm@1: HANDLE mapIOMEM; rlm@1: #endif rlm@1: rlm@1: int32 gbaSaveType = 0; // used to remember the save type on reset rlm@1: bool8 intState = false; rlm@1: bool8 stopState = false; rlm@1: bool8 holdState = false; rlm@1: int32 holdType = 0; rlm@1: bool8 cpuSramEnabled = true; rlm@1: bool8 cpuFlashEnabled = true; rlm@1: bool8 cpuEEPROMEnabled = true; rlm@1: bool8 cpuEEPROMSensorEnabled = false; rlm@1: rlm@1: #ifdef PROFILING rlm@1: int profilingTicks = 0; rlm@1: int profilingTicksReload = 0; rlm@1: static char *profilBuffer = NULL; rlm@1: static int profilSize = 0; rlm@1: static u32 profilLowPC = 0; rlm@1: static int profilScale = 0; rlm@1: #endif rlm@1: bool8 freezeWorkRAM[0x40000]; rlm@1: bool8 freezeInternalRAM[0x8000]; rlm@1: int32 lcdTicks = 960; rlm@1: bool8 timer0On = false; rlm@1: int32 timer0Ticks = 0; rlm@1: int32 timer0Reload = 0; rlm@1: int32 timer0ClockReload = 0; rlm@1: bool8 timer1On = false; rlm@1: int32 timer1Ticks = 0; rlm@1: int32 timer1Reload = 0; rlm@1: int32 timer1ClockReload = 0; rlm@1: bool8 timer2On = false; rlm@1: int32 timer2Ticks = 0; rlm@1: int32 timer2Reload = 0; rlm@1: int32 timer2ClockReload = 0; rlm@1: bool8 timer3On = false; rlm@1: int32 timer3Ticks = 0; rlm@1: int32 timer3Reload = 0; rlm@1: int32 timer3ClockReload = 0; rlm@1: u32 dma0Source = 0; rlm@1: u32 dma0Dest = 0; rlm@1: u32 dma1Source = 0; rlm@1: u32 dma1Dest = 0; rlm@1: u32 dma2Source = 0; rlm@1: u32 dma2Dest = 0; rlm@1: u32 dma3Source = 0; rlm@1: u32 dma3Dest = 0; rlm@1: void (*cpuSaveGameFunc)(u32, u8) = flashSaveDecide; rlm@1: void (*renderLine)() = mode0RenderLine; rlm@1: bool8 fxOn = false; rlm@1: bool8 windowOn = false; rlm@1: int32 frameSkipCount = 0; rlm@1: u32 gbaLastTime = 0; rlm@1: int32 gbaFrameCount = 0; rlm@1: bool8 prefetchActive = false, prefetchPrevActive = false, prefetchApplies = false; rlm@1: char buffer[1024]; rlm@1: FILE *out = NULL; rlm@1: rlm@1: static bool newFrame = true; rlm@1: static bool pauseAfterFrameAdvance = false; rlm@1: rlm@1: const int32 TIMER_TICKS[4] = { rlm@1: 1, rlm@1: 64, rlm@1: 256, rlm@1: 1024 rlm@1: }; rlm@1: rlm@1: const int32 thumbCycles[] = { rlm@1: // 0 1 2 3 4 5 6 7 8 9 a b c d e f rlm@1: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 rlm@1: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 rlm@1: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 rlm@1: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 rlm@1: 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4 rlm@1: 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5 rlm@1: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6 rlm@1: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7 rlm@1: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8 rlm@1: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9 rlm@1: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a rlm@1: 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b rlm@1: 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c rlm@1: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d rlm@1: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e rlm@1: 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f rlm@1: }; rlm@1: rlm@1: const int32 gamepakRamWaitState[4] = { 4, 3, 2, 8 }; rlm@1: const int32 gamepakWaitState[8] = { 4, 3, 2, 8, 4, 3, 2, 8 }; rlm@1: const int32 gamepakWaitState0[8] = { 2, 2, 2, 2, 1, 1, 1, 1 }; rlm@1: const int32 gamepakWaitState1[8] = { 4, 4, 4, 4, 1, 1, 1, 1 }; rlm@1: const int32 gamepakWaitState2[8] = { 8, 8, 8, 8, 1, 1, 1, 1 }; rlm@1: rlm@1: int32 memoryWait[16] = rlm@1: { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; rlm@1: int32 memoryWait32[16] = rlm@1: { 0, 0, 9, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0 }; rlm@1: int32 memoryWaitSeq[16] = rlm@1: { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 }; rlm@1: int32 memoryWaitSeq32[16] = rlm@1: { 2, 0, 3, 0, 0, 2, 2, 0, 4, 4, 8, 8, 16, 16, 8, 0 }; rlm@1: int32 memoryWaitFetch[16] = rlm@1: { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; rlm@1: int32 memoryWaitFetch32[16] = rlm@1: { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 }; rlm@1: rlm@1: const int32 cpuMemoryWait[16] = { rlm@1: 0, 0, 2, 0, 0, 0, 0, 0, rlm@1: 2, 2, 2, 2, 2, 2, 0, 0 rlm@1: }; rlm@1: const int32 cpuMemoryWait32[16] = { rlm@1: 0, 0, 3, 0, 0, 0, 0, 0, rlm@1: 3, 3, 3, 3, 3, 3, 0, 0 rlm@1: }; rlm@1: rlm@1: const bool8 memory32[16] = { rlm@1: true, false, false, true, true, false, false, true, false, false, false, false, false, false, true, false rlm@1: }; rlm@1: rlm@1: u8 biosProtected[4]; rlm@1: rlm@1: u8 cpuBitsSet[256]; rlm@1: u8 cpuLowestBitSet[256]; rlm@1: rlm@1: #ifdef WORDS_BIGENDIAN rlm@1: bool8 cpuBiosSwapped = false; rlm@1: #endif rlm@1: rlm@1: u32 myROM[] = { rlm@1: 0xEA000006, rlm@1: 0xEA000093, rlm@1: 0xEA000006, rlm@1: 0x00000000, rlm@1: 0x00000000, rlm@1: 0x00000000, rlm@1: 0xEA000088, rlm@1: 0x00000000, rlm@1: 0xE3A00302, rlm@1: 0xE1A0F000, rlm@1: 0xE92D5800, rlm@1: 0xE55EC002, rlm@1: 0xE28FB03C, rlm@1: 0xE79BC10C, rlm@1: 0xE14FB000, rlm@1: 0xE92D0800, rlm@1: 0xE20BB080, rlm@1: 0xE38BB01F, rlm@1: 0xE129F00B, rlm@1: 0xE92D4004, rlm@1: 0xE1A0E00F, rlm@1: 0xE12FFF1C, rlm@1: 0xE8BD4004, rlm@1: 0xE3A0C0D3, rlm@1: 0xE129F00C, rlm@1: 0xE8BD0800, rlm@1: 0xE169F00B, rlm@1: 0xE8BD5800, rlm@1: 0xE1B0F00E, rlm@1: 0x0000009C, rlm@1: 0x0000009C, rlm@1: 0x0000009C, rlm@1: 0x0000009C, rlm@1: 0x000001F8, rlm@1: 0x000001F0, rlm@1: 0x000000AC, rlm@1: 0x000000A0, rlm@1: 0x000000FC, rlm@1: 0x00000168, rlm@1: 0xE12FFF1E, rlm@1: 0xE1A03000, rlm@1: 0xE1A00001, rlm@1: 0xE1A01003, rlm@1: 0xE2113102, rlm@1: 0x42611000, rlm@1: 0xE033C040, rlm@1: 0x22600000, rlm@1: 0xE1B02001, rlm@1: 0xE15200A0, rlm@1: 0x91A02082, rlm@1: 0x3AFFFFFC, rlm@1: 0xE1500002, rlm@1: 0xE0A33003, rlm@1: 0x20400002, rlm@1: 0xE1320001, rlm@1: 0x11A020A2, rlm@1: 0x1AFFFFF9, rlm@1: 0xE1A01000, rlm@1: 0xE1A00003, rlm@1: 0xE1B0C08C, rlm@1: 0x22600000, rlm@1: 0x42611000, rlm@1: 0xE12FFF1E, rlm@1: 0xE92D0010, rlm@1: 0xE1A0C000, rlm@1: 0xE3A01001, rlm@1: 0xE1500001, rlm@1: 0x81A000A0, rlm@1: 0x81A01081, rlm@1: 0x8AFFFFFB, rlm@1: 0xE1A0000C, rlm@1: 0xE1A04001, rlm@1: 0xE3A03000, rlm@1: 0xE1A02001, rlm@1: 0xE15200A0, rlm@1: 0x91A02082, rlm@1: 0x3AFFFFFC, rlm@1: 0xE1500002, rlm@1: 0xE0A33003, rlm@1: 0x20400002, rlm@1: 0xE1320001, rlm@1: 0x11A020A2, rlm@1: 0x1AFFFFF9, rlm@1: 0xE0811003, rlm@1: 0xE1B010A1, rlm@1: 0xE1510004, rlm@1: 0x3AFFFFEE, rlm@1: 0xE1A00004, rlm@1: 0xE8BD0010, rlm@1: 0xE12FFF1E, rlm@1: 0xE0010090, rlm@1: 0xE1A01741, rlm@1: 0xE2611000, rlm@1: 0xE3A030A9, rlm@1: 0xE0030391, rlm@1: 0xE1A03743, rlm@1: 0xE2833E39, rlm@1: 0xE0030391, rlm@1: 0xE1A03743, rlm@1: 0xE2833C09, rlm@1: 0xE283301C, rlm@1: 0xE0030391, rlm@1: 0xE1A03743, rlm@1: 0xE2833C0F, rlm@1: 0xE28330B6, rlm@1: 0xE0030391, rlm@1: 0xE1A03743, rlm@1: 0xE2833C16, rlm@1: 0xE28330AA, rlm@1: 0xE0030391, rlm@1: 0xE1A03743, rlm@1: 0xE2833A02, rlm@1: 0xE2833081, rlm@1: 0xE0030391, rlm@1: 0xE1A03743, rlm@1: 0xE2833C36, rlm@1: 0xE2833051, rlm@1: 0xE0030391, rlm@1: 0xE1A03743, rlm@1: 0xE2833CA2, rlm@1: 0xE28330F9, rlm@1: 0xE0000093, rlm@1: 0xE1A00840, rlm@1: 0xE12FFF1E, rlm@1: 0xE3A00001, rlm@1: 0xE3A01001, rlm@1: 0xE92D4010, rlm@1: 0xE3A0C301, rlm@1: 0xE3A03000, rlm@1: 0xE3A04001, rlm@1: 0xE3500000, rlm@1: 0x1B000004, rlm@1: 0xE5CC3301, rlm@1: 0xEB000002, rlm@1: 0x0AFFFFFC, rlm@1: 0xE8BD4010, rlm@1: 0xE12FFF1E, rlm@1: 0xE5CC3208, rlm@1: 0xE15C20B8, rlm@1: 0xE0110002, rlm@1: 0x10200002, rlm@1: 0x114C00B8, rlm@1: 0xE5CC4208, rlm@1: 0xE12FFF1E, rlm@1: 0xE92D500F, rlm@1: 0xE3A00301, rlm@1: 0xE1A0E00F, rlm@1: 0xE510F004, rlm@1: 0xE8BD500F, rlm@1: 0xE25EF004, rlm@1: 0xE59FD044, rlm@1: 0xE92D5000, rlm@1: 0xE14FC000, rlm@1: 0xE10FE000, rlm@1: 0xE92D5000, rlm@1: 0xE3A0C302, rlm@1: 0xE5DCE09C, rlm@1: 0xE35E00A5, rlm@1: 0x1A000004, rlm@1: 0x05DCE0B4, rlm@1: 0x021EE080, rlm@1: 0xE28FE004, rlm@1: 0x159FF018, rlm@1: 0x059FF018, rlm@1: 0xE59FD018, rlm@1: 0xE8BD5000, rlm@1: 0xE169F00C, rlm@1: 0xE8BD5000, rlm@1: 0xE25EF004, rlm@1: 0x03007FF0, rlm@1: 0x09FE2000, rlm@1: 0x09FFC000, rlm@1: 0x03007FE0 rlm@1: }; rlm@1: rlm@1: variable_desc saveGameStruct[] = { rlm@1: { &DISPCNT, sizeof(u16) }, rlm@1: { &DISPSTAT, sizeof(u16) }, rlm@1: { &VCOUNT, sizeof(u16) }, rlm@1: { &BG0CNT, sizeof(u16) }, rlm@1: { &BG1CNT, sizeof(u16) }, rlm@1: { &BG2CNT, sizeof(u16) }, rlm@1: { &BG3CNT, sizeof(u16) }, rlm@1: { &BG0HOFS, sizeof(u16) }, rlm@1: { &BG0VOFS, sizeof(u16) }, rlm@1: { &BG1HOFS, sizeof(u16) }, rlm@1: { &BG1VOFS, sizeof(u16) }, rlm@1: { &BG2HOFS, sizeof(u16) }, rlm@1: { &BG2VOFS, sizeof(u16) }, rlm@1: { &BG3HOFS, sizeof(u16) }, rlm@1: { &BG3VOFS, sizeof(u16) }, rlm@1: { &BG2PA, sizeof(u16) }, rlm@1: { &BG2PB, sizeof(u16) }, rlm@1: { &BG2PC, sizeof(u16) }, rlm@1: { &BG2PD, sizeof(u16) }, rlm@1: { &BG2X_L, sizeof(u16) }, rlm@1: { &BG2X_H, sizeof(u16) }, rlm@1: { &BG2Y_L, sizeof(u16) }, rlm@1: { &BG2Y_H, sizeof(u16) }, rlm@1: { &BG3PA, sizeof(u16) }, rlm@1: { &BG3PB, sizeof(u16) }, rlm@1: { &BG3PC, sizeof(u16) }, rlm@1: { &BG3PD, sizeof(u16) }, rlm@1: { &BG3X_L, sizeof(u16) }, rlm@1: { &BG3X_H, sizeof(u16) }, rlm@1: { &BG3Y_L, sizeof(u16) }, rlm@1: { &BG3Y_H, sizeof(u16) }, rlm@1: { &WIN0H, sizeof(u16) }, rlm@1: { &WIN1H, sizeof(u16) }, rlm@1: { &WIN0V, sizeof(u16) }, rlm@1: { &WIN1V, sizeof(u16) }, rlm@1: { &WININ, sizeof(u16) }, rlm@1: { &WINOUT, sizeof(u16) }, rlm@1: { &MOSAIC, sizeof(u16) }, rlm@1: { &BLDMOD, sizeof(u16) }, rlm@1: { &COLEV, sizeof(u16) }, rlm@1: { &COLY, sizeof(u16) }, rlm@1: { &DM0SAD_L, sizeof(u16) }, rlm@1: { &DM0SAD_H, sizeof(u16) }, rlm@1: { &DM0DAD_L, sizeof(u16) }, rlm@1: { &DM0DAD_H, sizeof(u16) }, rlm@1: { &DM0CNT_L, sizeof(u16) }, rlm@1: { &DM0CNT_H, sizeof(u16) }, rlm@1: { &DM1SAD_L, sizeof(u16) }, rlm@1: { &DM1SAD_H, sizeof(u16) }, rlm@1: { &DM1DAD_L, sizeof(u16) }, rlm@1: { &DM1DAD_H, sizeof(u16) }, rlm@1: { &DM1CNT_L, sizeof(u16) }, rlm@1: { &DM1CNT_H, sizeof(u16) }, rlm@1: { &DM2SAD_L, sizeof(u16) }, rlm@1: { &DM2SAD_H, sizeof(u16) }, rlm@1: { &DM2DAD_L, sizeof(u16) }, rlm@1: { &DM2DAD_H, sizeof(u16) }, rlm@1: { &DM2CNT_L, sizeof(u16) }, rlm@1: { &DM2CNT_H, sizeof(u16) }, rlm@1: { &DM3SAD_L, sizeof(u16) }, rlm@1: { &DM3SAD_H, sizeof(u16) }, rlm@1: { &DM3DAD_L, sizeof(u16) }, rlm@1: { &DM3DAD_H, sizeof(u16) }, rlm@1: { &DM3CNT_L, sizeof(u16) }, rlm@1: { &DM3CNT_H, sizeof(u16) }, rlm@1: { &TM0D, sizeof(u16) }, rlm@1: { &TM0CNT, sizeof(u16) }, rlm@1: { &TM1D, sizeof(u16) }, rlm@1: { &TM1CNT, sizeof(u16) }, rlm@1: { &TM2D, sizeof(u16) }, rlm@1: { &TM2CNT, sizeof(u16) }, rlm@1: { &TM3D, sizeof(u16) }, rlm@1: { &TM3CNT, sizeof(u16) }, rlm@1: { &P1, sizeof(u16) }, rlm@1: { &IE, sizeof(u16) }, rlm@1: { &IF, sizeof(u16) }, rlm@1: { &IME, sizeof(u16) }, rlm@1: { &holdState, sizeof(bool8) }, rlm@1: { &holdType, sizeof(int32) }, rlm@1: { &lcdTicks, sizeof(int32) }, rlm@1: { &timer0On, sizeof(bool8) }, rlm@1: { &timer0Ticks, sizeof(int32) }, rlm@1: { &timer0Reload, sizeof(int32) }, rlm@1: { &timer0ClockReload, sizeof(int32) }, rlm@1: { &timer1On, sizeof(bool8) }, rlm@1: { &timer1Ticks, sizeof(int32) }, rlm@1: { &timer1Reload, sizeof(int32) }, rlm@1: { &timer1ClockReload, sizeof(int32) }, rlm@1: { &timer2On, sizeof(bool8) }, rlm@1: { &timer2Ticks, sizeof(int32) }, rlm@1: { &timer2Reload, sizeof(int32) }, rlm@1: { &timer2ClockReload, sizeof(int32) }, rlm@1: { &timer3On, sizeof(bool8) }, rlm@1: { &timer3Ticks, sizeof(int32) }, rlm@1: { &timer3Reload, sizeof(int32) }, rlm@1: { &timer3ClockReload, sizeof(int32) }, rlm@1: { &dma0Source, sizeof(u32) }, rlm@1: { &dma0Dest, sizeof(u32) }, rlm@1: { &dma1Source, sizeof(u32) }, rlm@1: { &dma1Dest, sizeof(u32) }, rlm@1: { &dma2Source, sizeof(u32) }, rlm@1: { &dma2Dest, sizeof(u32) }, rlm@1: { &dma3Source, sizeof(u32) }, rlm@1: { &dma3Dest, sizeof(u32) }, rlm@1: { &fxOn, sizeof(bool8) }, rlm@1: { &windowOn, sizeof(bool8) }, rlm@1: { &N_FLAG, sizeof(bool8) }, rlm@1: { &C_FLAG, sizeof(bool8) }, rlm@1: { &Z_FLAG, sizeof(bool8) }, rlm@1: { &V_FLAG, sizeof(bool8) }, rlm@1: { &armState, sizeof(bool8) }, rlm@1: { &armIrqEnable, sizeof(bool8) }, rlm@1: { &armNextPC, sizeof(u32) }, rlm@1: { &armMode, sizeof(int32) }, rlm@1: { &saveType, sizeof(int32) }, rlm@1: { NULL, 0 } rlm@1: }; rlm@1: rlm@1: //int cpuLoopTicks = 0; rlm@1: int cpuSavedTicks = 0; rlm@1: rlm@1: #ifdef PROFILING rlm@1: void cpuProfil(char *buf, int size, u32 lowPC, int scale) rlm@1: { rlm@1: profilBuffer = buf; rlm@1: profilSize = size; rlm@1: profilLowPC = lowPC; rlm@1: profilScale = scale; rlm@1: } rlm@1: rlm@1: void cpuEnableProfiling(int hz) rlm@1: { rlm@1: if (hz == 0) rlm@1: hz = 100; rlm@1: profilingTicks = profilingTicksReload = 16777216 / hz; rlm@1: profSetHertz(hz); rlm@1: } rlm@1: rlm@1: #endif rlm@1: rlm@1: inline int CPUUpdateTicksAccess32(u32 address) rlm@1: { rlm@1: return memoryWait32[(address >> 24) & 15]; rlm@1: } rlm@1: rlm@1: inline int CPUUpdateTicksAccess16(u32 address) rlm@1: { rlm@1: return memoryWait[(address >> 24) & 15]; rlm@1: } rlm@1: rlm@1: inline int CPUUpdateTicksAccessSeq32(u32 address) rlm@1: { rlm@1: return memoryWaitSeq32[(address >> 24) & 15]; rlm@1: } rlm@1: rlm@1: inline int CPUUpdateTicksAccessSeq16(u32 address) rlm@1: { rlm@1: return memoryWaitSeq[(address >> 24) & 15]; rlm@1: } rlm@1: rlm@1: inline int CPUUpdateTicks() rlm@1: { rlm@1: int cpuLoopTicks = lcdTicks; rlm@1: rlm@1: if (soundTicks < cpuLoopTicks) rlm@1: cpuLoopTicks = soundTicks; rlm@1: rlm@1: if (timer0On && !(TM0CNT & 4) && (timer0Ticks < cpuLoopTicks)) rlm@1: { rlm@1: cpuLoopTicks = timer0Ticks; rlm@1: } rlm@1: if (timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks)) rlm@1: { rlm@1: cpuLoopTicks = timer1Ticks; rlm@1: } rlm@1: if (timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks)) rlm@1: { rlm@1: cpuLoopTicks = timer2Ticks; rlm@1: } rlm@1: if (timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks)) rlm@1: { rlm@1: cpuLoopTicks = timer3Ticks; rlm@1: } rlm@1: #ifdef PROFILING rlm@1: if (profilingTicksReload != 0) rlm@1: { rlm@1: if (profilingTicks < cpuLoopTicks) rlm@1: { rlm@1: cpuLoopTicks = profilingTicks; rlm@1: } rlm@1: } rlm@1: #endif rlm@1: cpuSavedTicks = cpuLoopTicks; rlm@1: return cpuLoopTicks; rlm@1: } rlm@1: rlm@1: void CPUUpdateWindow0() rlm@1: { rlm@1: int x00 = WIN0H >> 8; rlm@1: int x01 = WIN0H & 255; rlm@1: rlm@1: if (x00 <= x01) rlm@1: { rlm@1: for (int i = 0; i < 240; i++) rlm@1: { rlm@1: gfxInWin0[i] = (i >= x00 && i < x01); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: for (int i = 0; i < 240; i++) rlm@1: { rlm@1: gfxInWin0[i] = (i >= x00 || i < x01); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUUpdateWindow1() rlm@1: { rlm@1: int x00 = WIN1H >> 8; rlm@1: int x01 = WIN1H & 255; rlm@1: rlm@1: if (x00 <= x01) rlm@1: { rlm@1: for (int i = 0; i < 240; i++) rlm@1: { rlm@1: gfxInWin1[i] = (i >= x00 && i < x01); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: for (int i = 0; i < 240; i++) rlm@1: { rlm@1: gfxInWin1[i] = (i >= x00 || i < x01); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: #define CLEAR_ARRAY(a) \ rlm@1: { \ rlm@1: u32 *array = (a); \ rlm@1: for (int i = 0; i < 240; i++) { \ rlm@1: *array++ = 0x80000000; \ rlm@1: } \ rlm@1: } \ rlm@1: rlm@1: void CPUUpdateRenderBuffers(bool force) rlm@1: { rlm@1: if (!(layerEnable & 0x0100) || force) rlm@1: { rlm@1: CLEAR_ARRAY(line0); rlm@1: } rlm@1: if (!(layerEnable & 0x0200) || force) rlm@1: { rlm@1: CLEAR_ARRAY(line1); rlm@1: } rlm@1: if (!(layerEnable & 0x0400) || force) rlm@1: { rlm@1: CLEAR_ARRAY(line2); rlm@1: } rlm@1: if (!(layerEnable & 0x0800) || force) rlm@1: { rlm@1: CLEAR_ARRAY(line3); rlm@1: } rlm@1: } rlm@1: rlm@1: bool CPUWriteStateToStream(gzFile gzFile) rlm@1: { rlm@1: utilWriteInt(gzFile, SAVE_GAME_VERSION); rlm@1: rlm@1: utilGzWrite(gzFile, &rom[0xa0], 16); rlm@1: rlm@1: utilWriteInt(gzFile, useBios); rlm@1: rlm@1: utilGzWrite(gzFile, ®[0], sizeof(reg)); rlm@1: rlm@1: utilWriteData(gzFile, saveGameStruct); rlm@1: rlm@1: // new to version 0.7.1 rlm@1: utilWriteInt(gzFile, stopState); rlm@1: // new to version 0.8 rlm@1: utilWriteInt(gzFile, intState); rlm@1: rlm@1: utilGzWrite(gzFile, internalRAM, 0x8000); rlm@1: utilGzWrite(gzFile, paletteRAM, 0x400); rlm@1: utilGzWrite(gzFile, workRAM, 0x40000); rlm@1: utilGzWrite(gzFile, vram, 0x20000); rlm@1: utilGzWrite(gzFile, oam, 0x400); rlm@1: utilGzWrite(gzFile, pix, 4 * 241 * 162); rlm@1: utilGzWrite(gzFile, ioMem, 0x400); rlm@1: rlm@1: eepromSaveGame(gzFile); rlm@1: flashSaveGame(gzFile); rlm@1: soundSaveGame(gzFile); rlm@1: rlm@1: cheatsSaveGame(gzFile); rlm@1: rlm@1: // version 1.5 rlm@1: rtcSaveGame(gzFile); rlm@1: rlm@1: // SAVE_GAME_VERSION_9 (new to re-recording version which is based on 1.72) rlm@1: { rlm@1: extern int32 sensorX, sensorY; // from SDL.cpp rlm@1: utilGzWrite(gzFile, &sensorX, sizeof(sensorX)); rlm@1: utilGzWrite(gzFile, &sensorY, sizeof(sensorY)); rlm@1: bool8 movieActive = VBAMovieActive(); rlm@1: utilGzWrite(gzFile, &movieActive, sizeof(movieActive)); rlm@1: if (movieActive) rlm@1: { rlm@1: uint8 *movie_freeze_buf = NULL; rlm@1: uint32 movie_freeze_size = 0; rlm@1: rlm@1: VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size); rlm@1: if (movie_freeze_buf) rlm@1: { rlm@1: utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size)); rlm@1: utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size); rlm@1: delete [] movie_freeze_buf; rlm@1: } rlm@1: else rlm@1: { rlm@1: systemMessage(0, N_("Failed to save movie snapshot.")); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: utilGzWrite(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount)); rlm@1: } rlm@1: rlm@1: // SAVE_GAME_VERSION_10 rlm@1: { rlm@1: utilGzWrite(gzFile, memoryWait, 16 * sizeof(int32)); rlm@1: utilGzWrite(gzFile, memoryWait32, 16 * sizeof(int32)); rlm@1: utilGzWrite(gzFile, memoryWaitSeq, 16 * sizeof(int32)); rlm@1: utilGzWrite(gzFile, memoryWaitSeq32, 16 * sizeof(int32)); rlm@1: utilGzWrite(gzFile, memoryWaitFetch, 16 * sizeof(int32)); rlm@1: utilGzWrite(gzFile, memoryWaitFetch32, 16 * sizeof(int32)); rlm@1: } rlm@1: rlm@1: // SAVE_GAME_VERSION_11 rlm@1: { rlm@1: utilGzWrite(gzFile, &prefetchActive, sizeof(bool8)); rlm@1: utilGzWrite(gzFile, &prefetchPrevActive, sizeof(bool8)); rlm@1: utilGzWrite(gzFile, &prefetchApplies, sizeof(bool8)); rlm@1: } rlm@1: rlm@1: // SAVE_GAME_VERSION_12 rlm@1: { rlm@1: utilGzWrite(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary rlm@1: utilGzWrite(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used... rlm@1: } rlm@1: rlm@1: // SAVE_GAME_VERSION_13 rlm@1: { rlm@1: utilGzWrite(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount)); rlm@1: utilGzWrite(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged)); rlm@1: utilGzWrite(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast)); rlm@1: } rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUWriteState(const char *file) rlm@1: { rlm@1: gzFile gzFile = utilGzOpen(file, "wb"); rlm@1: rlm@1: if (gzFile == NULL) rlm@1: { rlm@1: systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file); rlm@1: return false; rlm@1: } rlm@1: rlm@1: bool res = CPUWriteStateToStream(gzFile); rlm@1: rlm@1: utilGzClose(gzFile); rlm@1: rlm@1: return res; rlm@1: } rlm@1: rlm@1: bool CPUWriteMemState(char *memory, int available) rlm@1: { rlm@1: gzFile gzFile = utilMemGzOpen(memory, available, "w"); rlm@1: rlm@1: if (gzFile == NULL) rlm@1: { rlm@1: return false; rlm@1: } rlm@1: rlm@1: bool res = CPUWriteStateToStream(gzFile); rlm@1: rlm@1: long pos = utilGzTell(gzFile) + 8; rlm@1: rlm@1: if (pos >= (available)) rlm@1: res = false; rlm@1: rlm@1: utilGzClose(gzFile); rlm@1: rlm@1: return res; rlm@1: } rlm@1: rlm@1: static int tempStateID = 0; rlm@1: static int tempFailCount = 0; rlm@1: static bool backupSafe = true; rlm@1: rlm@1: bool CPUReadStateFromStream(gzFile gzFile) rlm@1: { rlm@1: bool8 ub; rlm@1: char tempBackupName [128]; rlm@1: if (backupSafe) rlm@1: { rlm@1: sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++); rlm@1: CPUWriteState(tempBackupName); rlm@1: } rlm@1: rlm@1: int version = utilReadInt(gzFile); rlm@1: rlm@1: if (version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1) rlm@1: { rlm@1: systemMessage(MSG_UNSUPPORTED_VBA_SGM, rlm@1: N_("Unsupported VisualBoyAdvance save game version %d"), rlm@1: version); rlm@1: goto failedLoad; rlm@1: } rlm@1: rlm@1: u8 romname[17]; rlm@1: rlm@1: utilGzRead(gzFile, romname, 16); rlm@1: rlm@1: if (memcmp(&rom[0xa0], romname, 16) != 0) rlm@1: { rlm@1: romname[16] = 0; rlm@1: for (int i = 0; i < 16; i++) rlm@1: if (romname[i] < 32) rlm@1: romname[i] = 32; rlm@1: systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname); rlm@1: goto failedLoad; rlm@1: } rlm@1: rlm@1: ub = utilReadInt(gzFile) ? true : false; rlm@1: rlm@1: if (ub != useBios) rlm@1: { rlm@1: if (useBios) rlm@1: systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, rlm@1: N_("Save game is not using the BIOS files")); rlm@1: else rlm@1: systemMessage(MSG_SAVE_GAME_USING_BIOS, rlm@1: N_("Save game is using the BIOS file")); rlm@1: goto failedLoad; rlm@1: } rlm@1: rlm@1: utilGzRead(gzFile, ®[0], sizeof(reg)); rlm@1: rlm@1: utilReadData(gzFile, saveGameStruct); rlm@1: rlm@1: if (version < SAVE_GAME_VERSION_3) rlm@1: stopState = false; rlm@1: else rlm@1: stopState = utilReadInt(gzFile) ? true : false; rlm@1: rlm@1: if (version < SAVE_GAME_VERSION_4) rlm@1: intState = false; rlm@1: else rlm@1: intState = utilReadInt(gzFile) ? true : false; rlm@1: rlm@1: utilGzRead(gzFile, internalRAM, 0x8000); rlm@1: utilGzRead(gzFile, paletteRAM, 0x400); rlm@1: utilGzRead(gzFile, workRAM, 0x40000); rlm@1: utilGzRead(gzFile, vram, 0x20000); rlm@1: utilGzRead(gzFile, oam, 0x400); rlm@1: if (version < SAVE_GAME_VERSION_6) rlm@1: utilGzRead(gzFile, pix, 4 * 240 * 160); rlm@1: else rlm@1: utilGzRead(gzFile, pix, 4 * 241 * 162); rlm@1: utilGzRead(gzFile, ioMem, 0x400); rlm@1: rlm@1: eepromReadGame(gzFile, version); rlm@1: flashReadGame(gzFile, version); rlm@1: soundReadGame(gzFile, version); rlm@1: rlm@1: if (version > SAVE_GAME_VERSION_1) rlm@1: { rlm@1: cheatsReadGame(gzFile); rlm@1: } rlm@1: if (version > SAVE_GAME_VERSION_6) rlm@1: { rlm@1: rtcReadGame(gzFile); rlm@1: } rlm@1: rlm@1: if (version <= SAVE_GAME_VERSION_7) rlm@1: { rlm@1: u32 temp; rlm@1: #define SWAP(a, b, c) \ rlm@1: temp = (a); \ rlm@1: (a) = (b) << 16 | (c); \ rlm@1: (b) = (temp) >> 16; \ rlm@1: (c) = (temp) & 0xFFFF; rlm@1: rlm@1: SWAP(dma0Source, DM0SAD_H, DM0SAD_L); rlm@1: SWAP(dma0Dest, DM0DAD_H, DM0DAD_L); rlm@1: SWAP(dma1Source, DM1SAD_H, DM1SAD_L); rlm@1: SWAP(dma1Dest, DM1DAD_H, DM1DAD_L); rlm@1: SWAP(dma2Source, DM2SAD_H, DM2SAD_L); rlm@1: SWAP(dma2Dest, DM2DAD_H, DM2DAD_L); rlm@1: SWAP(dma3Source, DM3SAD_H, DM3SAD_L); rlm@1: SWAP(dma3Dest, DM3DAD_H, DM3DAD_L); rlm@1: } rlm@1: rlm@1: // set pointers! rlm@1: layerEnable = layerSettings & DISPCNT; rlm@1: rlm@1: CPUUpdateRender(); rlm@1: CPUUpdateRenderBuffers(true); rlm@1: CPUUpdateWindow0(); rlm@1: CPUUpdateWindow1(); rlm@1: gbaSaveType = 0; rlm@1: switch (saveType) rlm@1: { rlm@1: case 0: rlm@1: cpuSaveGameFunc = flashSaveDecide; rlm@1: break; rlm@1: case 1: rlm@1: cpuSaveGameFunc = sramWrite; rlm@1: gbaSaveType = 1; rlm@1: break; rlm@1: case 2: rlm@1: cpuSaveGameFunc = flashWrite; rlm@1: gbaSaveType = 2; rlm@1: break; rlm@1: default: rlm@1: systemMessage(MSG_UNSUPPORTED_SAVE_TYPE, rlm@1: N_("Unsupported save type %d"), saveType); rlm@1: break; rlm@1: } rlm@1: if (eepromInUse) rlm@1: gbaSaveType = 3; rlm@1: rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; rlm@1: rlm@1: if (version >= SAVE_GAME_VERSION_9) // new to re-recording version: rlm@1: { rlm@1: extern int32 sensorX, sensorY; // from SDL.cpp rlm@1: utilGzRead(gzFile, &sensorX, sizeof(sensorX)); rlm@1: utilGzRead(gzFile, &sensorY, sizeof(sensorY)); rlm@1: rlm@1: bool8 movieSnapshot; rlm@1: utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot)); rlm@1: if (VBAMovieActive() && !movieSnapshot) rlm@1: { rlm@1: systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active.")); rlm@1: goto failedLoad; rlm@1: } rlm@1: rlm@1: if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added rlm@1: // later on in the save format rlm@1: { rlm@1: uint32 movieInputDataSize = 0; rlm@1: utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize)); rlm@1: uint8 *local_movie_data = new uint8[movieInputDataSize]; rlm@1: int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize); rlm@1: if (readBytes != movieInputDataSize) rlm@1: { rlm@1: systemMessage(0, N_("Corrupt movie snapshot.")); rlm@1: if (local_movie_data) rlm@1: delete [] local_movie_data; rlm@1: goto failedLoad; rlm@1: } rlm@1: int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize); rlm@1: if (local_movie_data) rlm@1: delete [] local_movie_data; rlm@1: if (code != MOVIE_SUCCESS && VBAMovieActive()) rlm@1: { rlm@1: char errStr [1024]; rlm@1: strcpy(errStr, "Failed to load movie snapshot"); rlm@1: switch (code) rlm@1: { rlm@1: case MOVIE_NOT_FROM_THIS_MOVIE: rlm@1: strcat(errStr, ";\nSnapshot not from this movie"); break; rlm@1: case MOVIE_NOT_FROM_A_MOVIE: rlm@1: strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here... rlm@1: case MOVIE_SNAPSHOT_INCONSISTENT: rlm@1: strcat(errStr, ";\nSnapshot inconsistent with movie"); break; rlm@1: case MOVIE_WRONG_FORMAT: rlm@1: strcat(errStr, ";\nWrong format"); break; rlm@1: } rlm@1: strcat(errStr, "."); rlm@1: systemMessage(0, N_(errStr)); rlm@1: goto failedLoad; rlm@1: } rlm@1: } rlm@1: utilGzRead(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount)); rlm@1: } rlm@1: if (version >= SAVE_GAME_VERSION_10) rlm@1: { rlm@1: utilGzRead(gzFile, memoryWait, 16 * sizeof(int32)); rlm@1: utilGzRead(gzFile, memoryWait32, 16 * sizeof(int32)); rlm@1: utilGzRead(gzFile, memoryWaitSeq, 16 * sizeof(int32)); rlm@1: utilGzRead(gzFile, memoryWaitSeq32, 16 * sizeof(int32)); rlm@1: utilGzRead(gzFile, memoryWaitFetch, 16 * sizeof(int32)); rlm@1: utilGzRead(gzFile, memoryWaitFetch32, 16 * sizeof(int32)); rlm@1: } rlm@1: if (version >= SAVE_GAME_VERSION_11) rlm@1: { rlm@1: utilGzRead(gzFile, &prefetchActive, sizeof(bool8)); rlm@1: //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600); rlm@1: //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600); rlm@1: utilGzRead(gzFile, &prefetchPrevActive, sizeof(bool8)); rlm@1: utilGzRead(gzFile, &prefetchApplies, sizeof(bool8)); rlm@1: } rlm@1: if (version >= SAVE_GAME_VERSION_12) rlm@1: { rlm@1: utilGzRead(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary rlm@1: utilGzRead(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used... rlm@1: } rlm@1: if (version >= SAVE_GAME_VERSION_13) rlm@1: { rlm@1: utilGzRead(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount)); rlm@1: utilGzRead(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged)); rlm@1: utilGzRead(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast)); rlm@1: } rlm@1: rlm@1: if (backupSafe) rlm@1: { rlm@1: remove(tempBackupName); rlm@1: tempFailCount = 0; rlm@1: } rlm@1: systemSetJoypad(0, ~P1 & 0x3FF); rlm@1: VBAUpdateButtonPressDisplay(); rlm@1: VBAUpdateFrameCountDisplay(); rlm@1: systemRefreshScreen(); rlm@1: return true; rlm@1: rlm@1: failedLoad: rlm@1: if (backupSafe) rlm@1: { rlm@1: tempFailCount++; rlm@1: if (tempFailCount < 3) // fail no more than 2 times in a row rlm@1: CPUReadState(tempBackupName); rlm@1: remove(tempBackupName); rlm@1: } rlm@1: return false; rlm@1: } rlm@1: rlm@1: bool CPUReadMemState(char *memory, int available) rlm@1: { rlm@1: gzFile gzFile = utilMemGzOpen(memory, available, "r"); rlm@1: rlm@1: backupSafe = false; rlm@1: bool res = CPUReadStateFromStream(gzFile); rlm@1: backupSafe = true; rlm@1: rlm@1: utilGzClose(gzFile); rlm@1: rlm@1: return res; rlm@1: } rlm@1: rlm@1: bool CPUReadState(const char *file) rlm@1: { rlm@1: gzFile gzFile = utilGzOpen(file, "rb"); rlm@1: rlm@1: if (gzFile == NULL) rlm@1: return false; rlm@1: rlm@1: bool res = CPUReadStateFromStream(gzFile); rlm@1: rlm@1: utilGzClose(gzFile); rlm@1: rlm@1: return res; rlm@1: } rlm@1: rlm@1: bool CPUExportEepromFile(const char *fileName) rlm@1: { rlm@1: if (eepromInUse) rlm@1: { rlm@1: FILE *file = fopen(fileName, "wb"); rlm@1: rlm@1: if (!file) rlm@1: { rlm@1: systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), rlm@1: fileName); rlm@1: return false; rlm@1: } rlm@1: rlm@1: for (int i = 0; i < eepromSize; ) rlm@1: { rlm@1: for (int j = 0; j < 8; j++) rlm@1: { rlm@1: if (fwrite(&eepromData[i + 7 - j], 1, 1, file) != 1) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: i += 8; rlm@1: } rlm@1: fclose(file); rlm@1: } rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUWriteBatteryToStream(gzFile gzFile) rlm@1: { rlm@1: if (!gzFile) rlm@1: return false; rlm@1: rlm@1: utilWriteInt(gzFile, SAVE_GAME_VERSION); rlm@1: rlm@1: // for simplicity, we put both types of battery files should be in the stream, even if one's empty rlm@1: eepromSaveGame(gzFile); rlm@1: flashSaveGame(gzFile); rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUWriteBatteryFile(const char *fileName) rlm@1: { rlm@1: if (gbaSaveType == 0) rlm@1: { rlm@1: if (eepromInUse) rlm@1: gbaSaveType = 3; rlm@1: else rlm@1: switch (saveType) rlm@1: { rlm@1: case 1: rlm@1: gbaSaveType = 1; rlm@1: break; rlm@1: case 2: rlm@1: gbaSaveType = 2; rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: if (gbaSaveType) rlm@1: { rlm@1: FILE *file = fopen(fileName, "wb"); rlm@1: rlm@1: if (!file) rlm@1: { rlm@1: systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), rlm@1: fileName); rlm@1: return false; rlm@1: } rlm@1: rlm@1: // only save if Flash/Sram in use or EEprom in use rlm@1: if (gbaSaveType != 3) rlm@1: { rlm@1: if (gbaSaveType == 2) rlm@1: { rlm@1: if (fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: fclose(file); rlm@1: } rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUReadGSASnapshot(const char *fileName) rlm@1: { rlm@1: int i; rlm@1: FILE *file = fopen(fileName, "rb"); rlm@1: rlm@1: if (!file) rlm@1: { rlm@1: systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); rlm@1: return false; rlm@1: } rlm@1: rlm@1: // check file size to know what we should read rlm@1: fseek(file, 0, SEEK_END); rlm@1: rlm@1: // long size = ftell(file); rlm@1: fseek(file, 0x0, SEEK_SET); rlm@1: fread(&i, 1, 4, file); rlm@1: fseek(file, i, SEEK_CUR); // Skip SharkPortSave rlm@1: fseek(file, 4, SEEK_CUR); // skip some sort of flag rlm@1: fread(&i, 1, 4, file); // name length rlm@1: fseek(file, i, SEEK_CUR); // skip name rlm@1: fread(&i, 1, 4, file); // desc length rlm@1: fseek(file, i, SEEK_CUR); // skip desc rlm@1: fread(&i, 1, 4, file); // notes length rlm@1: fseek(file, i, SEEK_CUR); // skip notes rlm@1: int saveSize; rlm@1: fread(&saveSize, 1, 4, file); // read length rlm@1: saveSize -= 0x1c; // remove header size rlm@1: char buffer[17]; rlm@1: char buffer2[17]; rlm@1: fread(buffer, 1, 16, file); rlm@1: buffer[16] = 0; rlm@1: for (i = 0; i < 16; i++) rlm@1: if (buffer[i] < 32) rlm@1: buffer[i] = 32; rlm@1: memcpy(buffer2, &rom[0xa0], 16); rlm@1: buffer2[16] = 0; rlm@1: for (i = 0; i < 16; i++) rlm@1: if (buffer2[i] < 32) rlm@1: buffer2[i] = 32; rlm@1: if (memcmp(buffer, buffer2, 16)) rlm@1: { rlm@1: systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, rlm@1: N_("Cannot import snapshot for %s. Current game is %s"), rlm@1: buffer, rlm@1: buffer2); rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: fseek(file, 12, SEEK_CUR); // skip some flags rlm@1: if (saveSize >= 65536) rlm@1: { rlm@1: if (fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, rlm@1: N_("Unsupported snapshot file %s"), rlm@1: fileName); rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: fclose(file); rlm@1: CPUReset(); rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUWriteGSASnapshot(const char *fileName, rlm@1: const char *title, rlm@1: const char *desc, rlm@1: const char *notes) rlm@1: { rlm@1: FILE *file = fopen(fileName, "wb"); rlm@1: rlm@1: if (!file) rlm@1: { rlm@1: systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); rlm@1: return false; rlm@1: } rlm@1: rlm@1: u8 buffer[17]; rlm@1: rlm@1: utilPutDword(buffer, 0x0d); // SharkPortSave length rlm@1: fwrite(buffer, 1, 4, file); rlm@1: fwrite("SharkPortSave", 1, 0x0d, file); rlm@1: utilPutDword(buffer, 0x000f0000); rlm@1: fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save rlm@1: utilPutDword(buffer, strlen(title)); rlm@1: fwrite(buffer, 1, 4, file); // title length rlm@1: fwrite(title, 1, strlen(title), file); rlm@1: utilPutDword(buffer, strlen(desc)); rlm@1: fwrite(buffer, 1, 4, file); // desc length rlm@1: fwrite(desc, 1, strlen(desc), file); rlm@1: utilPutDword(buffer, strlen(notes)); rlm@1: fwrite(buffer, 1, 4, file); // notes length rlm@1: fwrite(notes, 1, strlen(notes), file); rlm@1: int saveSize = 0x10000; rlm@1: if (gbaSaveType == 2) rlm@1: saveSize = flashSize; rlm@1: int totalSize = saveSize + 0x1c; rlm@1: rlm@1: utilPutDword(buffer, totalSize); // length of remainder of save - CRC rlm@1: fwrite(buffer, 1, 4, file); rlm@1: rlm@1: char temp[0x2001c]; rlm@1: memset(temp, 0, 28); rlm@1: memcpy(temp, &rom[0xa0], 16); // copy internal name rlm@1: temp[0x10] = rom[0xbe]; // reserved area (old checksum) rlm@1: temp[0x11] = rom[0xbf]; // reserved area (old checksum) rlm@1: temp[0x12] = rom[0xbd]; // complement check rlm@1: temp[0x13] = rom[0xb0]; // maker rlm@1: temp[0x14] = 1; // 1 save ? rlm@1: memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save rlm@1: fwrite(temp, 1, totalSize, file); // write save + header rlm@1: u32 crc = 0; rlm@1: rlm@1: for (int i = 0; i < totalSize; i++) rlm@1: { rlm@1: crc += ((u32)temp[i] << (crc % 0x18)); rlm@1: } rlm@1: rlm@1: utilPutDword(buffer, crc); rlm@1: fwrite(buffer, 1, 4, file); // CRC? rlm@1: rlm@1: fclose(file); rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUImportEepromFile(const char *fileName) rlm@1: { rlm@1: FILE *file = fopen(fileName, "rb"); rlm@1: rlm@1: if (!file) rlm@1: return false; rlm@1: rlm@1: // check file size to know what we should read rlm@1: fseek(file, 0, SEEK_END); rlm@1: rlm@1: long size = ftell(file); rlm@1: fseek(file, 0, SEEK_SET); rlm@1: if (size == 512 || size == 0x2000) rlm@1: { rlm@1: if (fread(eepromData, 1, size, file) != (size_t)size) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: for (int i = 0; i < size; ) rlm@1: { rlm@1: u8 tmp = eepromData[i]; rlm@1: eepromData[i] = eepromData[7 - i]; rlm@1: eepromData[7 - i] = tmp; rlm@1: i++; rlm@1: tmp = eepromData[i]; rlm@1: eepromData[i] = eepromData[7 - i]; rlm@1: eepromData[7 - i] = tmp; rlm@1: i++; rlm@1: tmp = eepromData[i]; rlm@1: eepromData[i] = eepromData[7 - i]; rlm@1: eepromData[7 - i] = tmp; rlm@1: i++; rlm@1: tmp = eepromData[i]; rlm@1: eepromData[i] = eepromData[7 - i]; rlm@1: eepromData[7 - i] = tmp; rlm@1: i++; rlm@1: i += 4; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: fclose(file); rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUReadBatteryFromStream(gzFile gzFile) rlm@1: { rlm@1: if (!gzFile) rlm@1: return false; rlm@1: rlm@1: int version = utilReadInt(gzFile); rlm@1: rlm@1: // for simplicity, we put both types of battery files should be in the stream, even if one's empty rlm@1: eepromReadGame(gzFile, version); rlm@1: flashReadGame(gzFile, version); rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUReadBatteryFile(const char *fileName) rlm@1: { rlm@1: FILE *file = fopen(fileName, "rb"); rlm@1: rlm@1: if (!file) rlm@1: return false; rlm@1: rlm@1: // check file size to know what we should read rlm@1: fseek(file, 0, SEEK_END); rlm@1: rlm@1: long size = ftell(file); rlm@1: fseek(file, 0, SEEK_SET); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; rlm@1: rlm@1: if (size == 512 || size == 0x2000) rlm@1: { rlm@1: if (fread(eepromData, 1, size, file) != (size_t)size) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (size == 0x20000) rlm@1: { rlm@1: if (fread(flashSaveMemory, 1, 0x20000, file) != 0x20000) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: flashSetSize(0x20000); rlm@1: } rlm@1: else rlm@1: { rlm@1: if (fread(flashSaveMemory, 1, 0x10000, file) != 0x10000) rlm@1: { rlm@1: fclose(file); rlm@1: return false; rlm@1: } rlm@1: flashSetSize(0x10000); rlm@1: } rlm@1: } rlm@1: fclose(file); rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool CPUWritePNGFile(const char *fileName) rlm@1: { rlm@1: return utilWritePNGFile(fileName, 240, 160, pix); rlm@1: } rlm@1: rlm@1: bool CPUWriteBMPFile(const char *fileName) rlm@1: { rlm@1: return utilWriteBMPFile(fileName, 240, 160, pix); rlm@1: } rlm@1: rlm@1: void CPUCleanUp() rlm@1: { rlm@1: newFrame = true; rlm@1: rlm@1: GBASystemCounters.frameCount = 0; rlm@1: GBASystemCounters.lagCount = 0; rlm@1: GBASystemCounters.extraCount = 0; rlm@1: GBASystemCounters.lagged = true; rlm@1: GBASystemCounters.laggedLast = true; rlm@1: rlm@1: #ifdef PROFILING rlm@1: if (profilingTicksReload) rlm@1: { rlm@1: profCleanup(); rlm@1: } rlm@1: #endif rlm@1: rlm@1: #if (defined(WIN32) && !defined(SDL)) rlm@1: #define FreeMappedMem(name, mapName, offset) \ rlm@1: if (name != NULL) { \ rlm@1: UnmapViewOfFile((name) - (offset)); \ rlm@1: name = NULL; \ rlm@1: CloseHandle(mapName); \ rlm@1: } rlm@1: #else rlm@1: #define FreeMappedMem(name, mapName, offset) \ rlm@1: if (name != NULL) { \ rlm@1: free(name); \ rlm@1: name = NULL; \ rlm@1: } rlm@1: #endif rlm@1: rlm@1: FreeMappedMem(rom, mapROM, 0); rlm@1: FreeMappedMem(vram, mapVRAM, 0); rlm@1: FreeMappedMem(paletteRAM, mapPALETTERAM, 0); rlm@1: FreeMappedMem(internalRAM, mapIRAM, 0); rlm@1: FreeMappedMem(workRAM, mapWORKRAM, 0); rlm@1: FreeMappedMem(bios, mapBIOS, 0); rlm@1: FreeMappedMem(pix, mapPIX, 4); rlm@1: FreeMappedMem(oam, mapOAM, 0); rlm@1: FreeMappedMem(ioMem, mapIOMEM, 0); rlm@1: rlm@1: eepromErase(); rlm@1: flashErase(); rlm@1: rlm@1: elfCleanUp(); rlm@1: rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; rlm@1: rlm@1: systemClearJoypads(); rlm@1: systemResetSensor(); rlm@1: rlm@1: // gbaLastTime = gbaFrameCount = 0; rlm@1: systemRefreshScreen(); rlm@1: } rlm@1: rlm@1: int CPULoadRom(const char *szFile) rlm@1: { rlm@1: int size = 0x2000000; rlm@1: rlm@1: if (rom != NULL) rlm@1: { rlm@1: CPUCleanUp(); rlm@1: } rlm@1: rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; rlm@1: rlm@1: // size+4 is so RAM search and watch are safe to read any byte in the allocated region as a 4-byte int rlm@1: #if (defined(WIN32) && !defined(SDL)) rlm@1: #define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \ rlm@1: mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), nameStr); \ rlm@1: if ((mapName) && GetLastError() == ERROR_ALREADY_EXISTS) { \ rlm@1: CloseHandle(mapName); \ rlm@1: mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), NULL); \ rlm@1: } \ rlm@1: name = (u8 *)MapViewOfFile(mapName, FILE_MAP_WRITE, 0, 0, 0) + (offset); \ rlm@1: if ((name) == NULL) { \ rlm@1: systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \ rlm@1: CPUCleanUp(); \ rlm@1: return 0; \ rlm@1: } \ rlm@1: memset(name, 0, size + 4); rlm@1: #else rlm@1: #define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \ rlm@1: name = (u8 *)(useCalloc ? calloc(1, size + 4) : malloc(size + 4)); \ rlm@1: if ((name) == NULL) { \ rlm@1: systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \ rlm@1: CPUCleanUp(); \ rlm@1: return 0; \ rlm@1: } \ rlm@1: memset(name, 0, size + 4); rlm@1: #endif rlm@1: rlm@1: AllocMappedMem(rom, mapROM, "vbaROM", 0x2000000, false, 0); rlm@1: AllocMappedMem(workRAM, mapWORKRAM, "vbaWORKRAM", 0x40000, true, 0); rlm@1: rlm@1: u8 *whereToLoad = rom; rlm@1: if (cpuIsMultiBoot) rlm@1: whereToLoad = workRAM; rlm@1: rlm@1: if (utilIsELF(szFile)) rlm@1: { rlm@1: FILE *f = fopen(szFile, "rb"); rlm@1: if (!f) rlm@1: { rlm@1: systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), rlm@1: szFile); rlm@1: FreeMappedMem(rom, mapROM, 0); rlm@1: FreeMappedMem(workRAM, mapWORKRAM, 0); rlm@1: return 0; rlm@1: } rlm@1: bool res = elfRead(szFile, size, f); rlm@1: if (!res || size == 0) rlm@1: { rlm@1: FreeMappedMem(rom, mapROM, 0); rlm@1: FreeMappedMem(workRAM, mapWORKRAM, 0); rlm@1: elfCleanUp(); rlm@1: return 0; rlm@1: } rlm@1: } rlm@1: else if (!utilLoad(szFile, rlm@1: utilIsGBAImage, rlm@1: whereToLoad, rlm@1: size)) rlm@1: { rlm@1: FreeMappedMem(rom, mapROM, 0); rlm@1: FreeMappedMem(workRAM, mapWORKRAM, 0); rlm@1: return 0; rlm@1: } rlm@1: rlm@1: u16 *temp = (u16 *)(rom + ((size + 1) & ~1)); rlm@1: int i; rlm@1: for (i = (size + 1) & ~1; i < 0x2000000; i += 2) rlm@1: { rlm@1: WRITE16LE(temp, (i >> 1) & 0xFFFF); rlm@1: temp++; rlm@1: } rlm@1: rlm@1: AllocMappedMem(bios, mapBIOS, "vbaBIOS", 0x4000, true, 0); rlm@1: AllocMappedMem(internalRAM, mapIRAM, "vbaIRAM", 0x8000, true, 0); rlm@1: AllocMappedMem(paletteRAM, mapPALETTERAM, "vbaPALETTERAM", 0x400, true, 0); rlm@1: AllocMappedMem(vram, mapVRAM, "vbaVRAM", 0x20000, true, 0); rlm@1: AllocMappedMem(oam, mapOAM, "vbaOAM", 0x400, true, 0); rlm@1: rlm@1: // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel rlm@1: AllocMappedMem(pix, mapPIX, "vbaPIX", 4 * 241 * 162, true, 4); rlm@1: AllocMappedMem(ioMem, mapIOMEM, "vbaIOMEM", 0x400, true, 0); rlm@1: rlm@1: CPUUpdateRenderBuffers(true); rlm@1: rlm@1: return size; rlm@1: } rlm@1: rlm@1: void CPUUpdateRender() rlm@1: { rlm@1: switch (DISPCNT & 7) rlm@1: { rlm@1: case 0: rlm@1: if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || rlm@1: cpuDisableSfx) rlm@1: renderLine = mode0RenderLine; rlm@1: else if (fxOn && !windowOn && !(layerEnable & 0x8000)) rlm@1: renderLine = mode0RenderLineNoWindow; rlm@1: else rlm@1: renderLine = mode0RenderLineAll; rlm@1: break; rlm@1: case 1: rlm@1: if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || rlm@1: cpuDisableSfx) rlm@1: renderLine = mode1RenderLine; rlm@1: else if (fxOn && !windowOn && !(layerEnable & 0x8000)) rlm@1: renderLine = mode1RenderLineNoWindow; rlm@1: else rlm@1: renderLine = mode1RenderLineAll; rlm@1: break; rlm@1: case 2: rlm@1: if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || rlm@1: cpuDisableSfx) rlm@1: renderLine = mode2RenderLine; rlm@1: else if (fxOn && !windowOn && !(layerEnable & 0x8000)) rlm@1: renderLine = mode2RenderLineNoWindow; rlm@1: else rlm@1: renderLine = mode2RenderLineAll; rlm@1: break; rlm@1: case 3: rlm@1: if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || rlm@1: cpuDisableSfx) rlm@1: renderLine = mode3RenderLine; rlm@1: else if (fxOn && !windowOn && !(layerEnable & 0x8000)) rlm@1: renderLine = mode3RenderLineNoWindow; rlm@1: else rlm@1: renderLine = mode3RenderLineAll; rlm@1: break; rlm@1: case 4: rlm@1: if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || rlm@1: cpuDisableSfx) rlm@1: renderLine = mode4RenderLine; rlm@1: else if (fxOn && !windowOn && !(layerEnable & 0x8000)) rlm@1: renderLine = mode4RenderLineNoWindow; rlm@1: else rlm@1: renderLine = mode4RenderLineAll; rlm@1: break; rlm@1: case 5: rlm@1: if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) || rlm@1: cpuDisableSfx) rlm@1: renderLine = mode5RenderLine; rlm@1: else if (fxOn && !windowOn && !(layerEnable & 0x8000)) rlm@1: renderLine = mode5RenderLineNoWindow; rlm@1: else rlm@1: renderLine = mode5RenderLineAll; rlm@1: default: rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUUpdateCPSR() rlm@1: { rlm@1: u32 CPSR = reg[16].I & 0x40; rlm@1: if (N_FLAG) rlm@1: CPSR |= 0x80000000; rlm@1: if (Z_FLAG) rlm@1: CPSR |= 0x40000000; rlm@1: if (C_FLAG) rlm@1: CPSR |= 0x20000000; rlm@1: if (V_FLAG) rlm@1: CPSR |= 0x10000000; rlm@1: if (!armState) rlm@1: CPSR |= 0x00000020; rlm@1: if (!armIrqEnable) rlm@1: CPSR |= 0x80; rlm@1: CPSR |= (armMode & 0x1F); rlm@1: reg[16].I = CPSR; rlm@1: } rlm@1: rlm@1: void CPUUpdateFlags(bool breakLoop) rlm@1: { rlm@1: u32 CPSR = reg[16].I; rlm@1: rlm@1: N_FLAG = (CPSR & 0x80000000) ? true : false; rlm@1: Z_FLAG = (CPSR & 0x40000000) ? true : false; rlm@1: C_FLAG = (CPSR & 0x20000000) ? true : false; rlm@1: V_FLAG = (CPSR & 0x10000000) ? true : false; rlm@1: armState = (CPSR & 0x20) ? false : true; rlm@1: armIrqEnable = (CPSR & 0x80) ? false : true; rlm@1: if (breakLoop) rlm@1: { rlm@1: if (armIrqEnable && (IF & IE) && (IME & 1)) rlm@1: { rlm@1: CPU_BREAK_LOOP_2; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUUpdateFlags() rlm@1: { rlm@1: CPUUpdateFlags(true); rlm@1: } rlm@1: rlm@1: #ifdef WORDS_BIGENDIAN rlm@1: static void CPUSwap(volatile u32 *a, volatile u32 *b) rlm@1: { rlm@1: volatile u32 c = *b; rlm@1: *b = *a; rlm@1: *a = c; rlm@1: } rlm@1: rlm@1: #else rlm@1: static void CPUSwap(u32 *a, u32 *b) rlm@1: { rlm@1: u32 c = *b; rlm@1: *b = *a; rlm@1: *a = c; rlm@1: } rlm@1: rlm@1: #endif rlm@1: rlm@1: void CPUSwitchMode(int mode, bool saveState, bool breakLoop) rlm@1: { rlm@1: // if(armMode == mode) rlm@1: // return; rlm@1: rlm@1: CPUUpdateCPSR(); rlm@1: rlm@1: switch (armMode) rlm@1: { rlm@1: case 0x10: rlm@1: case 0x1F: rlm@1: reg[R13_USR].I = reg[13].I; rlm@1: reg[R14_USR].I = reg[14].I; rlm@1: reg[17].I = reg[16].I; rlm@1: break; rlm@1: case 0x11: rlm@1: CPUSwap(®[R8_FIQ].I, ®[8].I); rlm@1: CPUSwap(®[R9_FIQ].I, ®[9].I); rlm@1: CPUSwap(®[R10_FIQ].I, ®[10].I); rlm@1: CPUSwap(®[R11_FIQ].I, ®[11].I); rlm@1: CPUSwap(®[R12_FIQ].I, ®[12].I); rlm@1: reg[R13_FIQ].I = reg[13].I; rlm@1: reg[R14_FIQ].I = reg[14].I; rlm@1: reg[SPSR_FIQ].I = reg[17].I; rlm@1: break; rlm@1: case 0x12: rlm@1: reg[R13_IRQ].I = reg[13].I; rlm@1: reg[R14_IRQ].I = reg[14].I; rlm@1: reg[SPSR_IRQ].I = reg[17].I; rlm@1: break; rlm@1: case 0x13: rlm@1: reg[R13_SVC].I = reg[13].I; rlm@1: reg[R14_SVC].I = reg[14].I; rlm@1: reg[SPSR_SVC].I = reg[17].I; rlm@1: break; rlm@1: case 0x17: rlm@1: reg[R13_ABT].I = reg[13].I; rlm@1: reg[R14_ABT].I = reg[14].I; rlm@1: reg[SPSR_ABT].I = reg[17].I; rlm@1: break; rlm@1: case 0x1b: rlm@1: reg[R13_UND].I = reg[13].I; rlm@1: reg[R14_UND].I = reg[14].I; rlm@1: reg[SPSR_UND].I = reg[17].I; rlm@1: break; rlm@1: } rlm@1: rlm@1: u32 CPSR = reg[16].I; rlm@1: u32 SPSR = reg[17].I; rlm@1: rlm@1: switch (mode) rlm@1: { rlm@1: case 0x10: rlm@1: case 0x1F: rlm@1: reg[13].I = reg[R13_USR].I; rlm@1: reg[14].I = reg[R14_USR].I; rlm@1: reg[16].I = SPSR; rlm@1: break; rlm@1: case 0x11: rlm@1: CPUSwap(®[8].I, ®[R8_FIQ].I); rlm@1: CPUSwap(®[9].I, ®[R9_FIQ].I); rlm@1: CPUSwap(®[10].I, ®[R10_FIQ].I); rlm@1: CPUSwap(®[11].I, ®[R11_FIQ].I); rlm@1: CPUSwap(®[12].I, ®[R12_FIQ].I); rlm@1: reg[13].I = reg[R13_FIQ].I; rlm@1: reg[14].I = reg[R14_FIQ].I; rlm@1: if (saveState) rlm@1: reg[17].I = CPSR; rlm@1: else rlm@1: reg[17].I = reg[SPSR_FIQ].I; rlm@1: break; rlm@1: case 0x12: rlm@1: reg[13].I = reg[R13_IRQ].I; rlm@1: reg[14].I = reg[R14_IRQ].I; rlm@1: reg[16].I = SPSR; rlm@1: if (saveState) rlm@1: reg[17].I = CPSR; rlm@1: else rlm@1: reg[17].I = reg[SPSR_IRQ].I; rlm@1: break; rlm@1: case 0x13: rlm@1: reg[13].I = reg[R13_SVC].I; rlm@1: reg[14].I = reg[R14_SVC].I; rlm@1: reg[16].I = SPSR; rlm@1: if (saveState) rlm@1: reg[17].I = CPSR; rlm@1: else rlm@1: reg[17].I = reg[SPSR_SVC].I; rlm@1: break; rlm@1: case 0x17: rlm@1: reg[13].I = reg[R13_ABT].I; rlm@1: reg[14].I = reg[R14_ABT].I; rlm@1: reg[16].I = SPSR; rlm@1: if (saveState) rlm@1: reg[17].I = CPSR; rlm@1: else rlm@1: reg[17].I = reg[SPSR_ABT].I; rlm@1: break; rlm@1: case 0x1b: rlm@1: reg[13].I = reg[R13_UND].I; rlm@1: reg[14].I = reg[R14_UND].I; rlm@1: reg[16].I = SPSR; rlm@1: if (saveState) rlm@1: reg[17].I = CPSR; rlm@1: else rlm@1: reg[17].I = reg[SPSR_UND].I; rlm@1: break; rlm@1: default: rlm@1: systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode); rlm@1: break; rlm@1: } rlm@1: armMode = mode; rlm@1: CPUUpdateFlags(breakLoop); rlm@1: CPUUpdateCPSR(); rlm@1: } rlm@1: rlm@1: void CPUSwitchMode(int mode, bool saveState) rlm@1: { rlm@1: CPUSwitchMode(mode, saveState, true); rlm@1: } rlm@1: rlm@1: void CPUUndefinedException() rlm@1: { rlm@1: u32 PC = reg[15].I; rlm@1: bool savedArmState = armState; rlm@1: CPUSwitchMode(0x1b, true, false); rlm@1: reg[14].I = PC - (savedArmState ? 4 : 2); rlm@1: reg[15].I = 0x04; rlm@1: armState = true; rlm@1: armIrqEnable = false; rlm@1: armNextPC = 0x04; rlm@1: reg[15].I += 4; rlm@1: } rlm@1: rlm@1: void CPUSoftwareInterrupt() rlm@1: { rlm@1: u32 PC = reg[15].I; rlm@1: bool savedArmState = armState; rlm@1: CPUSwitchMode(0x13, true, false); rlm@1: reg[14].I = PC - (savedArmState ? 4 : 2); rlm@1: reg[15].I = 0x08; rlm@1: armState = true; rlm@1: armIrqEnable = false; rlm@1: armNextPC = 0x08; rlm@1: reg[15].I += 4; rlm@1: } rlm@1: rlm@1: void CPUSoftwareInterrupt(int comment) rlm@1: { rlm@1: static bool disableMessage = false; rlm@1: if (armState) rlm@1: comment >>= 16; rlm@1: #ifdef BKPT_SUPPORT rlm@1: if (comment == 0xff) rlm@1: { rlm@1: extern void (*dbgOutput)(char *, u32); rlm@1: dbgOutput(NULL, reg[0].I); rlm@1: return; rlm@1: } rlm@1: #endif rlm@1: #ifdef PROFILING rlm@1: if (comment == 0xfe) rlm@1: { rlm@1: profStartup(reg[0].I, reg[1].I); rlm@1: return; rlm@1: } rlm@1: if (comment == 0xfd) rlm@1: { rlm@1: profControl(reg[0].I); rlm@1: return; rlm@1: } rlm@1: if (comment == 0xfc) rlm@1: { rlm@1: profCleanup(); rlm@1: return; rlm@1: } rlm@1: if (comment == 0xfb) rlm@1: { rlm@1: profCount(); rlm@1: return; rlm@1: } rlm@1: #endif rlm@1: if (comment == 0xfa) rlm@1: { rlm@1: agbPrintFlush(); rlm@1: return; rlm@1: } rlm@1: #ifdef SDL rlm@1: if (comment == 0xf9) rlm@1: { rlm@1: emulating = 0; rlm@1: CPU_BREAK_LOOP_2; rlm@1: return; rlm@1: } rlm@1: #endif rlm@1: if (useBios) rlm@1: { rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_SWI) rlm@1: { rlm@1: log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, rlm@1: armState ? armNextPC - 4 : armNextPC - 2, rlm@1: reg[0].I, rlm@1: reg[1].I, rlm@1: reg[2].I, rlm@1: VCOUNT); rlm@1: } rlm@1: #endif rlm@1: CPUSoftwareInterrupt(); rlm@1: return; rlm@1: } rlm@1: // This would be correct, but it causes problems if uncommented rlm@1: // else { rlm@1: // biosProtected = 0xe3a02004; rlm@1: // } rlm@1: rlm@1: switch (comment) rlm@1: { rlm@1: case 0x00: rlm@1: BIOS_SoftReset(); rlm@1: break; rlm@1: case 0x01: rlm@1: BIOS_RegisterRamReset(); rlm@1: break; rlm@1: case 0x02: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_SWI) rlm@1: { rlm@1: log("Halt: (VCOUNT = %2d)\n", rlm@1: VCOUNT); rlm@1: } rlm@1: #endif rlm@1: holdState = true; rlm@1: holdType = -1; rlm@1: break; rlm@1: case 0x03: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_SWI) rlm@1: { rlm@1: log("Stop: (VCOUNT = %2d)\n", rlm@1: VCOUNT); rlm@1: } rlm@1: #endif rlm@1: holdState = true; rlm@1: holdType = -1; rlm@1: stopState = true; rlm@1: break; rlm@1: case 0x04: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_SWI) rlm@1: { rlm@1: log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n", rlm@1: reg[0].I, rlm@1: reg[1].I, rlm@1: VCOUNT); rlm@1: } rlm@1: #endif rlm@1: CPUSoftwareInterrupt(); rlm@1: break; rlm@1: case 0x05: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_SWI) rlm@1: { rlm@1: log("VBlankIntrWait: (VCOUNT = %2d)\n", rlm@1: VCOUNT); rlm@1: } rlm@1: #endif rlm@1: CPUSoftwareInterrupt(); rlm@1: break; rlm@1: case 0x06: rlm@1: CPUSoftwareInterrupt(); rlm@1: break; rlm@1: case 0x07: rlm@1: CPUSoftwareInterrupt(); rlm@1: break; rlm@1: case 0x08: rlm@1: BIOS_Sqrt(); rlm@1: break; rlm@1: case 0x09: rlm@1: BIOS_ArcTan(); rlm@1: break; rlm@1: case 0x0A: rlm@1: BIOS_ArcTan2(); rlm@1: break; rlm@1: case 0x0B: rlm@1: BIOS_CpuSet(); rlm@1: break; rlm@1: case 0x0C: rlm@1: BIOS_CpuFastSet(); rlm@1: break; rlm@1: case 0x0E: rlm@1: BIOS_BgAffineSet(); rlm@1: break; rlm@1: case 0x0F: rlm@1: BIOS_ObjAffineSet(); rlm@1: break; rlm@1: case 0x10: rlm@1: BIOS_BitUnPack(); rlm@1: break; rlm@1: case 0x11: rlm@1: BIOS_LZ77UnCompWram(); rlm@1: break; rlm@1: case 0x12: rlm@1: BIOS_LZ77UnCompVram(); rlm@1: break; rlm@1: case 0x13: rlm@1: BIOS_HuffUnComp(); rlm@1: break; rlm@1: case 0x14: rlm@1: BIOS_RLUnCompWram(); rlm@1: break; rlm@1: case 0x15: rlm@1: BIOS_RLUnCompVram(); rlm@1: break; rlm@1: case 0x16: rlm@1: BIOS_Diff8bitUnFilterWram(); rlm@1: break; rlm@1: case 0x17: rlm@1: BIOS_Diff8bitUnFilterVram(); rlm@1: break; rlm@1: case 0x18: rlm@1: BIOS_Diff16bitUnFilter(); rlm@1: break; rlm@1: case 0x19: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_SWI) rlm@1: { rlm@1: log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n", rlm@1: reg[0].I, rlm@1: VCOUNT); rlm@1: } rlm@1: #endif rlm@1: if (reg[0].I) rlm@1: soundPause(); rlm@1: else rlm@1: soundResume(); rlm@1: break; rlm@1: case 0x1F: rlm@1: BIOS_MidiKey2Freq(); rlm@1: break; rlm@1: case 0x2A: rlm@1: BIOS_SndDriverJmpTableCopy(); rlm@1: // let it go, because we don't really emulate this function // FIXME (?) rlm@1: default: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_SWI) rlm@1: { rlm@1: log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, rlm@1: armState ? armNextPC - 4 : armNextPC - 2, rlm@1: reg[0].I, rlm@1: reg[1].I, rlm@1: reg[2].I, rlm@1: VCOUNT); rlm@1: } rlm@1: #endif rlm@1: rlm@1: if (!disableMessage) rlm@1: { rlm@1: systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION, rlm@1: N_( rlm@1: "Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."), rlm@1: comment, rlm@1: armMode ? armNextPC - 4 : armNextPC - 2); rlm@1: disableMessage = true; rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUCompareVCOUNT() rlm@1: { rlm@1: if (VCOUNT == (DISPSTAT >> 8)) rlm@1: { rlm@1: DISPSTAT |= 4; rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: rlm@1: if (DISPSTAT & 0x20) rlm@1: { rlm@1: IF |= 4; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: DISPSTAT &= 0xFFFB; rlm@1: UPDATE_REG(0x4, DISPSTAT); rlm@1: } rlm@1: } rlm@1: rlm@1: void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32) rlm@1: { rlm@1: int sm = s >> 24; rlm@1: int dm = d >> 24; rlm@1: rlm@1: int sc = c; rlm@1: rlm@1: cpuDmaCount = c; rlm@1: rlm@1: if (transfer32) rlm@1: { rlm@1: s &= 0xFFFFFFFC; rlm@1: if (s < 0x02000000 && (reg[15].I >> 24)) rlm@1: { rlm@1: while (c != 0) rlm@1: { rlm@1: CPUWriteMemory(d, 0); rlm@1: d += di; rlm@1: c--; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: while (c != 0) rlm@1: { rlm@1: CPUWriteMemory(d, CPUReadMemory(s)); rlm@1: d += di; rlm@1: s += si; rlm@1: c--; rlm@1: } rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: s &= 0xFFFFFFFE; rlm@1: si = (int)si >> 1; rlm@1: di = (int)di >> 1; rlm@1: if (s < 0x02000000 && (reg[15].I >> 24)) rlm@1: { rlm@1: while (c != 0) rlm@1: { rlm@1: CPUWriteHalfWord(d, 0); rlm@1: d += di; rlm@1: c--; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: while (c != 0) rlm@1: { rlm@1: cpuDmaLast = CPUReadHalfWord(s); rlm@1: CPUWriteHalfWord(d, cpuDmaLast); rlm@1: d += di; rlm@1: s += si; rlm@1: c--; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: cpuDmaCount = 0; rlm@1: rlm@1: int sw = 1 + memoryWaitSeq[sm & 15]; rlm@1: int dw = 1 + memoryWaitSeq[dm & 15]; rlm@1: rlm@1: int totalTicks = 0; rlm@1: rlm@1: if (transfer32) rlm@1: { rlm@1: if (!memory32[sm & 15]) rlm@1: sw <<= 1; rlm@1: if (!memory32[dm & 15]) rlm@1: dw <<= 1; rlm@1: } rlm@1: rlm@1: totalTicks = (sw + dw) * sc; rlm@1: rlm@1: cpuDmaTicksToUpdate += totalTicks; rlm@1: rlm@1: if (*extCpuLoopTicks >= 0) rlm@1: { rlm@1: CPU_BREAK_LOOP; rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUCheckDMA(int reason, int dmamask) rlm@1: { rlm@1: cpuDmaHack = 0; rlm@1: // DMA 0 rlm@1: if ((DM0CNT_H & 0x8000) && (dmamask & 1)) rlm@1: { rlm@1: if (((DM0CNT_H >> 12) & 3) == reason) rlm@1: { rlm@1: u32 sourceIncrement = 4; rlm@1: u32 destIncrement = 4; rlm@1: switch ((DM0CNT_H >> 7) & 3) rlm@1: { rlm@1: case 0: rlm@1: break; rlm@1: case 1: rlm@1: sourceIncrement = (u32) - 4; rlm@1: break; rlm@1: case 2: rlm@1: sourceIncrement = 0; rlm@1: break; rlm@1: } rlm@1: switch ((DM0CNT_H >> 5) & 3) rlm@1: { rlm@1: case 0: rlm@1: break; rlm@1: case 1: rlm@1: destIncrement = (u32) - 4; rlm@1: break; rlm@1: case 2: rlm@1: destIncrement = 0; rlm@1: break; rlm@1: } rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_DMA0) rlm@1: { rlm@1: int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1; rlm@1: if (DM0CNT_H & 0x0400) rlm@1: count <<= 1; rlm@1: log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest, rlm@1: DM0CNT_H, rlm@1: count); rlm@1: } rlm@1: #endif rlm@1: doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement, rlm@1: DM0CNT_L ? DM0CNT_L : 0x4000, rlm@1: DM0CNT_H & 0x0400); rlm@1: cpuDmaHack = 1; rlm@1: if (DM0CNT_H & 0x4000) rlm@1: { rlm@1: IF |= 0x0100; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: rlm@1: if (((DM0CNT_H >> 5) & 3) == 3) rlm@1: { rlm@1: dma0Dest = DM0DAD_L | (DM0DAD_H << 16); rlm@1: } rlm@1: rlm@1: if (!(DM0CNT_H & 0x0200) || (reason == 0)) rlm@1: { rlm@1: DM0CNT_H &= 0x7FFF; rlm@1: UPDATE_REG(0xBA, DM0CNT_H); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: // DMA 1 rlm@1: if ((DM1CNT_H & 0x8000) && (dmamask & 2)) rlm@1: { rlm@1: if (((DM1CNT_H >> 12) & 3) == reason) rlm@1: { rlm@1: u32 sourceIncrement = 4; rlm@1: u32 destIncrement = 4; rlm@1: switch ((DM1CNT_H >> 7) & 3) rlm@1: { rlm@1: case 0: rlm@1: break; rlm@1: case 1: rlm@1: sourceIncrement = (u32) - 4; rlm@1: break; rlm@1: case 2: rlm@1: sourceIncrement = 0; rlm@1: break; rlm@1: } rlm@1: switch ((DM1CNT_H >> 5) & 3) rlm@1: { rlm@1: case 0: rlm@1: break; rlm@1: case 1: rlm@1: destIncrement = (u32) - 4; rlm@1: break; rlm@1: case 2: rlm@1: destIncrement = 0; rlm@1: break; rlm@1: } rlm@1: if (reason == 3) rlm@1: { rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_DMA1) rlm@1: { rlm@1: log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, rlm@1: DM1CNT_H, rlm@1: 16); rlm@1: } rlm@1: #endif rlm@1: doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4, rlm@1: 0x0400); rlm@1: } rlm@1: else rlm@1: { rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_DMA1) rlm@1: { rlm@1: int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1; rlm@1: if (DM1CNT_H & 0x0400) rlm@1: count <<= 1; rlm@1: log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, rlm@1: DM1CNT_H, rlm@1: count); rlm@1: } rlm@1: #endif rlm@1: doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement, rlm@1: DM1CNT_L ? DM1CNT_L : 0x4000, rlm@1: DM1CNT_H & 0x0400); rlm@1: } rlm@1: cpuDmaHack = 1; rlm@1: rlm@1: if (DM1CNT_H & 0x4000) rlm@1: { rlm@1: IF |= 0x0200; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: rlm@1: if (((DM1CNT_H >> 5) & 3) == 3) rlm@1: { rlm@1: dma1Dest = DM1DAD_L | (DM1DAD_H << 16); rlm@1: } rlm@1: rlm@1: if (!(DM1CNT_H & 0x0200) || (reason == 0)) rlm@1: { rlm@1: DM1CNT_H &= 0x7FFF; rlm@1: UPDATE_REG(0xC6, DM1CNT_H); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: // DMA 2 rlm@1: if ((DM2CNT_H & 0x8000) && (dmamask & 4)) rlm@1: { rlm@1: if (((DM2CNT_H >> 12) & 3) == reason) rlm@1: { rlm@1: u32 sourceIncrement = 4; rlm@1: u32 destIncrement = 4; rlm@1: switch ((DM2CNT_H >> 7) & 3) rlm@1: { rlm@1: case 0: rlm@1: break; rlm@1: case 1: rlm@1: sourceIncrement = (u32) - 4; rlm@1: break; rlm@1: case 2: rlm@1: sourceIncrement = 0; rlm@1: break; rlm@1: } rlm@1: switch ((DM2CNT_H >> 5) & 3) rlm@1: { rlm@1: case 0: rlm@1: break; rlm@1: case 1: rlm@1: destIncrement = (u32) - 4; rlm@1: break; rlm@1: case 2: rlm@1: destIncrement = 0; rlm@1: break; rlm@1: } rlm@1: if (reason == 3) rlm@1: { rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_DMA2) rlm@1: { rlm@1: int count = (4) << 2; rlm@1: log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, rlm@1: DM2CNT_H, rlm@1: count); rlm@1: } rlm@1: #endif rlm@1: doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4, rlm@1: 0x0400); rlm@1: } rlm@1: else rlm@1: { rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_DMA2) rlm@1: { rlm@1: int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1; rlm@1: if (DM2CNT_H & 0x0400) rlm@1: count <<= 1; rlm@1: log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, rlm@1: DM2CNT_H, rlm@1: count); rlm@1: } rlm@1: #endif rlm@1: doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement, rlm@1: DM2CNT_L ? DM2CNT_L : 0x4000, rlm@1: DM2CNT_H & 0x0400); rlm@1: } rlm@1: cpuDmaHack = 1; rlm@1: if (DM2CNT_H & 0x4000) rlm@1: { rlm@1: IF |= 0x0400; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: rlm@1: if (((DM2CNT_H >> 5) & 3) == 3) rlm@1: { rlm@1: dma2Dest = DM2DAD_L | (DM2DAD_H << 16); rlm@1: } rlm@1: rlm@1: if (!(DM2CNT_H & 0x0200) || (reason == 0)) rlm@1: { rlm@1: DM2CNT_H &= 0x7FFF; rlm@1: UPDATE_REG(0xD2, DM2CNT_H); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: // DMA 3 rlm@1: if ((DM3CNT_H & 0x8000) && (dmamask & 8)) rlm@1: { rlm@1: if (((DM3CNT_H >> 12) & 3) == reason) rlm@1: { rlm@1: u32 sourceIncrement = 4; rlm@1: u32 destIncrement = 4; rlm@1: switch ((DM3CNT_H >> 7) & 3) rlm@1: { rlm@1: case 0: rlm@1: break; rlm@1: case 1: rlm@1: sourceIncrement = (u32) - 4; rlm@1: break; rlm@1: case 2: rlm@1: sourceIncrement = 0; rlm@1: break; rlm@1: } rlm@1: switch ((DM3CNT_H >> 5) & 3) rlm@1: { rlm@1: case 0: rlm@1: break; rlm@1: case 1: rlm@1: destIncrement = (u32) - 4; rlm@1: break; rlm@1: case 2: rlm@1: destIncrement = 0; rlm@1: break; rlm@1: } rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_DMA3) rlm@1: { rlm@1: int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1; rlm@1: if (DM3CNT_H & 0x0400) rlm@1: count <<= 1; rlm@1: log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest, rlm@1: DM3CNT_H, rlm@1: count); rlm@1: } rlm@1: #endif rlm@1: doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement, rlm@1: DM3CNT_L ? DM3CNT_L : 0x10000, rlm@1: DM3CNT_H & 0x0400); rlm@1: if (DM3CNT_H & 0x4000) rlm@1: { rlm@1: IF |= 0x0800; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: rlm@1: if (((DM3CNT_H >> 5) & 3) == 3) rlm@1: { rlm@1: dma3Dest = DM3DAD_L | (DM3DAD_H << 16); rlm@1: } rlm@1: rlm@1: if (!(DM3CNT_H & 0x0200) || (reason == 0)) rlm@1: { rlm@1: DM3CNT_H &= 0x7FFF; rlm@1: UPDATE_REG(0xDE, DM3CNT_H); rlm@1: } rlm@1: } rlm@1: } rlm@1: cpuDmaHack = 0; rlm@1: } rlm@1: rlm@1: void CPUUpdateRegister(u32 address, u16 value) rlm@1: { rlm@1: switch (address) rlm@1: { rlm@1: case 0x00: rlm@1: { rlm@1: bool change = ((DISPCNT ^ value) & 0x80) ? true : false; rlm@1: bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false; rlm@1: DISPCNT = (value & 0xFFF7); rlm@1: UPDATE_REG(0x00, DISPCNT); rlm@1: layerEnable = layerSettings & value; rlm@1: windowOn = (layerEnable & 0x6000) ? true : false; rlm@1: if (change && !((value & 0x80))) rlm@1: { rlm@1: if (!(DISPSTAT & 1)) rlm@1: { rlm@1: lcdTicks = 960; rlm@1: // VCOUNT = 0; rlm@1: // UPDATE_REG(0x06, VCOUNT); rlm@1: DISPSTAT &= 0xFFFC; rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: CPUCompareVCOUNT(); rlm@1: } rlm@1: // (*renderLine)(); rlm@1: } rlm@1: CPUUpdateRender(); rlm@1: // we only care about changes in BG0-BG3 rlm@1: if (changeBG) rlm@1: CPUUpdateRenderBuffers(false); rlm@1: // CPUUpdateTicks(); rlm@1: break; rlm@1: } rlm@1: case 0x04: rlm@1: DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7); rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: break; rlm@1: case 0x06: rlm@1: // not writable rlm@1: break; rlm@1: case 0x08: rlm@1: BG0CNT = (value & 0xDFCF); rlm@1: UPDATE_REG(0x08, BG0CNT); rlm@1: break; rlm@1: case 0x0A: rlm@1: BG1CNT = (value & 0xDFCF); rlm@1: UPDATE_REG(0x0A, BG1CNT); rlm@1: break; rlm@1: case 0x0C: rlm@1: BG2CNT = (value & 0xFFCF); rlm@1: UPDATE_REG(0x0C, BG2CNT); rlm@1: break; rlm@1: case 0x0E: rlm@1: BG3CNT = (value & 0xFFCF); rlm@1: UPDATE_REG(0x0E, BG3CNT); rlm@1: break; rlm@1: case 0x10: rlm@1: BG0HOFS = value & 511; rlm@1: UPDATE_REG(0x10, BG0HOFS); rlm@1: break; rlm@1: case 0x12: rlm@1: BG0VOFS = value & 511; rlm@1: UPDATE_REG(0x12, BG0VOFS); rlm@1: break; rlm@1: case 0x14: rlm@1: BG1HOFS = value & 511; rlm@1: UPDATE_REG(0x14, BG1HOFS); rlm@1: break; rlm@1: case 0x16: rlm@1: BG1VOFS = value & 511; rlm@1: UPDATE_REG(0x16, BG1VOFS); rlm@1: break; rlm@1: case 0x18: rlm@1: BG2HOFS = value & 511; rlm@1: UPDATE_REG(0x18, BG2HOFS); rlm@1: break; rlm@1: case 0x1A: rlm@1: BG2VOFS = value & 511; rlm@1: UPDATE_REG(0x1A, BG2VOFS); rlm@1: break; rlm@1: case 0x1C: rlm@1: BG3HOFS = value & 511; rlm@1: UPDATE_REG(0x1C, BG3HOFS); rlm@1: break; rlm@1: case 0x1E: rlm@1: BG3VOFS = value & 511; rlm@1: UPDATE_REG(0x1E, BG3VOFS); rlm@1: break; rlm@1: case 0x20: rlm@1: BG2PA = value; rlm@1: UPDATE_REG(0x20, BG2PA); rlm@1: break; rlm@1: case 0x22: rlm@1: BG2PB = value; rlm@1: UPDATE_REG(0x22, BG2PB); rlm@1: break; rlm@1: case 0x24: rlm@1: BG2PC = value; rlm@1: UPDATE_REG(0x24, BG2PC); rlm@1: break; rlm@1: case 0x26: rlm@1: BG2PD = value; rlm@1: UPDATE_REG(0x26, BG2PD); rlm@1: break; rlm@1: case 0x28: rlm@1: BG2X_L = value; rlm@1: UPDATE_REG(0x28, BG2X_L); rlm@1: gfxBG2Changed |= 1; rlm@1: break; rlm@1: case 0x2A: rlm@1: BG2X_H = (value & 0xFFF); rlm@1: UPDATE_REG(0x2A, BG2X_H); rlm@1: gfxBG2Changed |= 1; rlm@1: break; rlm@1: case 0x2C: rlm@1: BG2Y_L = value; rlm@1: UPDATE_REG(0x2C, BG2Y_L); rlm@1: gfxBG2Changed |= 2; rlm@1: break; rlm@1: case 0x2E: rlm@1: BG2Y_H = value & 0xFFF; rlm@1: UPDATE_REG(0x2E, BG2Y_H); rlm@1: gfxBG2Changed |= 2; rlm@1: break; rlm@1: case 0x30: rlm@1: BG3PA = value; rlm@1: UPDATE_REG(0x30, BG3PA); rlm@1: break; rlm@1: case 0x32: rlm@1: BG3PB = value; rlm@1: UPDATE_REG(0x32, BG3PB); rlm@1: break; rlm@1: case 0x34: rlm@1: BG3PC = value; rlm@1: UPDATE_REG(0x34, BG3PC); rlm@1: break; rlm@1: case 0x36: rlm@1: BG3PD = value; rlm@1: UPDATE_REG(0x36, BG3PD); rlm@1: break; rlm@1: case 0x38: rlm@1: BG3X_L = value; rlm@1: UPDATE_REG(0x38, BG3X_L); rlm@1: gfxBG3Changed |= 1; rlm@1: break; rlm@1: case 0x3A: rlm@1: BG3X_H = value & 0xFFF; rlm@1: UPDATE_REG(0x3A, BG3X_H); rlm@1: gfxBG3Changed |= 1; rlm@1: break; rlm@1: case 0x3C: rlm@1: BG3Y_L = value; rlm@1: UPDATE_REG(0x3C, BG3Y_L); rlm@1: gfxBG3Changed |= 2; rlm@1: break; rlm@1: case 0x3E: rlm@1: BG3Y_H = value & 0xFFF; rlm@1: UPDATE_REG(0x3E, BG3Y_H); rlm@1: gfxBG3Changed |= 2; rlm@1: break; rlm@1: case 0x40: rlm@1: WIN0H = value; rlm@1: UPDATE_REG(0x40, WIN0H); rlm@1: CPUUpdateWindow0(); rlm@1: break; rlm@1: case 0x42: rlm@1: WIN1H = value; rlm@1: UPDATE_REG(0x42, WIN1H); rlm@1: CPUUpdateWindow1(); rlm@1: break; rlm@1: case 0x44: rlm@1: WIN0V = value; rlm@1: UPDATE_REG(0x44, WIN0V); rlm@1: break; rlm@1: case 0x46: rlm@1: WIN1V = value; rlm@1: UPDATE_REG(0x46, WIN1V); rlm@1: break; rlm@1: case 0x48: rlm@1: WININ = value & 0x3F3F; rlm@1: UPDATE_REG(0x48, WININ); rlm@1: break; rlm@1: case 0x4A: rlm@1: WINOUT = value & 0x3F3F; rlm@1: UPDATE_REG(0x4A, WINOUT); rlm@1: break; rlm@1: case 0x4C: rlm@1: MOSAIC = value; rlm@1: UPDATE_REG(0x4C, MOSAIC); rlm@1: break; rlm@1: case 0x50: rlm@1: BLDMOD = value & 0x3FFF; rlm@1: UPDATE_REG(0x50, BLDMOD); rlm@1: fxOn = ((BLDMOD >> 6) & 3) != 0; rlm@1: CPUUpdateRender(); rlm@1: break; rlm@1: case 0x52: rlm@1: COLEV = value & 0x1F1F; rlm@1: UPDATE_REG(0x52, COLEV); rlm@1: break; rlm@1: case 0x54: rlm@1: COLY = value & 0x1F; rlm@1: UPDATE_REG(0x54, COLY); rlm@1: break; rlm@1: case 0x60: rlm@1: case 0x62: rlm@1: case 0x64: rlm@1: case 0x68: rlm@1: case 0x6c: rlm@1: case 0x70: rlm@1: case 0x72: rlm@1: case 0x74: rlm@1: case 0x78: rlm@1: case 0x7c: rlm@1: case 0x80: rlm@1: case 0x84: rlm@1: soundEvent(address & 0xFF, (u8)(value & 0xFF)); rlm@1: soundEvent((address & 0xFF) + 1, (u8)(value >> 8)); rlm@1: break; rlm@1: case 0x82: rlm@1: case 0x88: rlm@1: case 0xa0: rlm@1: case 0xa2: rlm@1: case 0xa4: rlm@1: case 0xa6: rlm@1: case 0x90: rlm@1: case 0x92: rlm@1: case 0x94: rlm@1: case 0x96: rlm@1: case 0x98: rlm@1: case 0x9a: rlm@1: case 0x9c: rlm@1: case 0x9e: rlm@1: soundEvent(address & 0xFF, value); rlm@1: break; rlm@1: case 0xB0: rlm@1: DM0SAD_L = value; rlm@1: UPDATE_REG(0xB0, DM0SAD_L); rlm@1: break; rlm@1: case 0xB2: rlm@1: DM0SAD_H = value & 0x07FF; rlm@1: UPDATE_REG(0xB2, DM0SAD_H); rlm@1: break; rlm@1: case 0xB4: rlm@1: DM0DAD_L = value; rlm@1: UPDATE_REG(0xB4, DM0DAD_L); rlm@1: break; rlm@1: case 0xB6: rlm@1: DM0DAD_H = value & 0x07FF; rlm@1: UPDATE_REG(0xB6, DM0DAD_H); rlm@1: break; rlm@1: case 0xB8: rlm@1: DM0CNT_L = value & 0x3FFF; rlm@1: UPDATE_REG(0xB8, 0); rlm@1: break; rlm@1: case 0xBA: rlm@1: { rlm@1: bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false; rlm@1: value &= 0xF7E0; rlm@1: rlm@1: DM0CNT_H = value; rlm@1: UPDATE_REG(0xBA, DM0CNT_H); rlm@1: rlm@1: if (start && (value & 0x8000)) rlm@1: { rlm@1: dma0Source = DM0SAD_L | (DM0SAD_H << 16); rlm@1: dma0Dest = DM0DAD_L | (DM0DAD_H << 16); rlm@1: CPUCheckDMA(0, 1); rlm@1: } rlm@1: break; rlm@1: } rlm@1: case 0xBC: rlm@1: DM1SAD_L = value; rlm@1: UPDATE_REG(0xBC, DM1SAD_L); rlm@1: break; rlm@1: case 0xBE: rlm@1: DM1SAD_H = value & 0x0FFF; rlm@1: UPDATE_REG(0xBE, DM1SAD_H); rlm@1: break; rlm@1: case 0xC0: rlm@1: DM1DAD_L = value; rlm@1: UPDATE_REG(0xC0, DM1DAD_L); rlm@1: break; rlm@1: case 0xC2: rlm@1: DM1DAD_H = value & 0x07FF; rlm@1: UPDATE_REG(0xC2, DM1DAD_H); rlm@1: break; rlm@1: case 0xC4: rlm@1: DM1CNT_L = value & 0x3FFF; rlm@1: UPDATE_REG(0xC4, 0); rlm@1: break; rlm@1: case 0xC6: rlm@1: { rlm@1: bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false; rlm@1: value &= 0xF7E0; rlm@1: rlm@1: DM1CNT_H = value; rlm@1: UPDATE_REG(0xC6, DM1CNT_H); rlm@1: rlm@1: if (start && (value & 0x8000)) rlm@1: { rlm@1: dma1Source = DM1SAD_L | (DM1SAD_H << 16); rlm@1: dma1Dest = DM1DAD_L | (DM1DAD_H << 16); rlm@1: CPUCheckDMA(0, 2); rlm@1: } rlm@1: break; rlm@1: } rlm@1: case 0xC8: rlm@1: DM2SAD_L = value; rlm@1: UPDATE_REG(0xC8, DM2SAD_L); rlm@1: break; rlm@1: case 0xCA: rlm@1: DM2SAD_H = value & 0x0FFF; rlm@1: UPDATE_REG(0xCA, DM2SAD_H); rlm@1: break; rlm@1: case 0xCC: rlm@1: DM2DAD_L = value; rlm@1: UPDATE_REG(0xCC, DM2DAD_L); rlm@1: break; rlm@1: case 0xCE: rlm@1: DM2DAD_H = value & 0x07FF; rlm@1: UPDATE_REG(0xCE, DM2DAD_H); rlm@1: break; rlm@1: case 0xD0: rlm@1: DM2CNT_L = value & 0x3FFF; rlm@1: UPDATE_REG(0xD0, 0); rlm@1: break; rlm@1: case 0xD2: rlm@1: { rlm@1: bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false; rlm@1: rlm@1: value &= 0xF7E0; rlm@1: rlm@1: DM2CNT_H = value; rlm@1: UPDATE_REG(0xD2, DM2CNT_H); rlm@1: rlm@1: if (start && (value & 0x8000)) rlm@1: { rlm@1: dma2Source = DM2SAD_L | (DM2SAD_H << 16); rlm@1: dma2Dest = DM2DAD_L | (DM2DAD_H << 16); rlm@1: rlm@1: CPUCheckDMA(0, 4); rlm@1: } rlm@1: break; rlm@1: } rlm@1: case 0xD4: rlm@1: DM3SAD_L = value; rlm@1: UPDATE_REG(0xD4, DM3SAD_L); rlm@1: break; rlm@1: case 0xD6: rlm@1: DM3SAD_H = value & 0x0FFF; rlm@1: UPDATE_REG(0xD6, DM3SAD_H); rlm@1: break; rlm@1: case 0xD8: rlm@1: DM3DAD_L = value; rlm@1: UPDATE_REG(0xD8, DM3DAD_L); rlm@1: break; rlm@1: case 0xDA: rlm@1: DM3DAD_H = value & 0x0FFF; rlm@1: UPDATE_REG(0xDA, DM3DAD_H); rlm@1: break; rlm@1: case 0xDC: rlm@1: DM3CNT_L = value; rlm@1: UPDATE_REG(0xDC, 0); rlm@1: break; rlm@1: case 0xDE: rlm@1: { rlm@1: bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false; rlm@1: rlm@1: value &= 0xFFE0; rlm@1: rlm@1: DM3CNT_H = value; rlm@1: UPDATE_REG(0xDE, DM3CNT_H); rlm@1: rlm@1: if (start && (value & 0x8000)) rlm@1: { rlm@1: dma3Source = DM3SAD_L | (DM3SAD_H << 16); rlm@1: dma3Dest = DM3DAD_L | (DM3DAD_H << 16); rlm@1: CPUCheckDMA(0, 8); rlm@1: } rlm@1: break; rlm@1: } rlm@1: case 0x100: rlm@1: timer0Reload = value; rlm@1: break; rlm@1: case 0x102: rlm@1: timer0Ticks = timer0ClockReload = TIMER_TICKS[value & 3]; rlm@1: if (!timer0On && (value & 0x80)) rlm@1: { rlm@1: // reload the counter rlm@1: TM0D = timer0Reload; rlm@1: if (timer0ClockReload == 1) rlm@1: timer0Ticks = 0x10000 - TM0D; rlm@1: UPDATE_REG(0x100, TM0D); rlm@1: } rlm@1: timer0On = value & 0x80 ? true : false; rlm@1: TM0CNT = value & 0xC7; rlm@1: UPDATE_REG(0x102, TM0CNT); rlm@1: // CPUUpdateTicks(); rlm@1: break; rlm@1: case 0x104: rlm@1: timer1Reload = value; rlm@1: break; rlm@1: case 0x106: rlm@1: timer1Ticks = timer1ClockReload = TIMER_TICKS[value & 3]; rlm@1: if (!timer1On && (value & 0x80)) rlm@1: { rlm@1: // reload the counter rlm@1: TM1D = timer1Reload; rlm@1: if (timer1ClockReload == 1) rlm@1: timer1Ticks = 0x10000 - TM1D; rlm@1: UPDATE_REG(0x104, TM1D); rlm@1: } rlm@1: timer1On = value & 0x80 ? true : false; rlm@1: TM1CNT = value & 0xC7; rlm@1: UPDATE_REG(0x106, TM1CNT); rlm@1: break; rlm@1: case 0x108: rlm@1: timer2Reload = value; rlm@1: break; rlm@1: case 0x10A: rlm@1: timer2Ticks = timer2ClockReload = TIMER_TICKS[value & 3]; rlm@1: if (!timer2On && (value & 0x80)) rlm@1: { rlm@1: // reload the counter rlm@1: TM2D = timer2Reload; rlm@1: if (timer2ClockReload == 1) rlm@1: timer2Ticks = 0x10000 - TM2D; rlm@1: UPDATE_REG(0x108, TM2D); rlm@1: } rlm@1: timer2On = value & 0x80 ? true : false; rlm@1: TM2CNT = value & 0xC7; rlm@1: UPDATE_REG(0x10A, TM2CNT); rlm@1: break; rlm@1: case 0x10C: rlm@1: timer3Reload = value; rlm@1: break; rlm@1: case 0x10E: rlm@1: timer3Ticks = timer3ClockReload = TIMER_TICKS[value & 3]; rlm@1: if (!timer3On && (value & 0x80)) rlm@1: { rlm@1: // reload the counter rlm@1: TM3D = timer3Reload; rlm@1: if (timer3ClockReload == 1) rlm@1: timer3Ticks = 0x10000 - TM3D; rlm@1: UPDATE_REG(0x10C, TM3D); rlm@1: } rlm@1: timer3On = value & 0x80 ? true : false; rlm@1: TM3CNT = value & 0xC7; rlm@1: UPDATE_REG(0x10E, TM3CNT); rlm@1: break; rlm@1: case 0x128: rlm@1: if (value & 0x80) rlm@1: { rlm@1: value &= 0xff7f; rlm@1: if (value & 1 && (value & 0x4000)) rlm@1: { rlm@1: UPDATE_REG(0x12a, 0xFF); rlm@1: IF |= 0x80; rlm@1: UPDATE_REG(0x202, IF); rlm@1: value &= 0x7f7f; rlm@1: } rlm@1: } rlm@1: UPDATE_REG(0x128, value); rlm@1: break; rlm@1: case 0x130: rlm@1: P1 |= (value & 0x3FF); rlm@1: UPDATE_REG(0x130, P1); rlm@1: break; rlm@1: case 0x132: rlm@1: UPDATE_REG(0x132, value & 0xC3FF); rlm@1: break; rlm@1: case 0x200: rlm@1: IE = value & 0x3FFF; rlm@1: UPDATE_REG(0x200, IE); rlm@1: if ((IME & 1) && (IF & IE) && armIrqEnable) rlm@1: { rlm@1: CPU_BREAK_LOOP_2; rlm@1: } rlm@1: break; rlm@1: case 0x202: rlm@1: IF ^= (value & IF); rlm@1: UPDATE_REG(0x202, IF); rlm@1: break; rlm@1: case 0x204: rlm@1: { rlm@1: int i; rlm@1: memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3]; rlm@1: rlm@1: if (!speedHack) rlm@1: { rlm@1: memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 7]; rlm@1: memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = rlm@1: gamepakWaitState0[(value >> 2) & 7]; rlm@1: rlm@1: memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 7]; rlm@1: memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = rlm@1: gamepakWaitState1[(value >> 5) & 7]; rlm@1: rlm@1: memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 7]; rlm@1: memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = rlm@1: gamepakWaitState2[(value >> 8) & 7]; rlm@1: } rlm@1: else rlm@1: { rlm@1: memoryWait[0x08] = memoryWait[0x09] = 4; rlm@1: memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 2; rlm@1: rlm@1: memoryWait[0x0a] = memoryWait[0x0b] = 4; rlm@1: memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 4; rlm@1: rlm@1: memoryWait[0x0c] = memoryWait[0x0d] = 4; rlm@1: memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 8; rlm@1: } rlm@1: for (i = 0; i < 16; i++) rlm@1: { rlm@1: memoryWaitFetch32[i] = memoryWait32[i] = memoryWait[i] * rlm@1: (memory32[i] ? 1 : 2); rlm@1: memoryWaitFetch[i] = memoryWait[i]; rlm@1: } rlm@1: memoryWaitFetch32[3] += 1; rlm@1: memoryWaitFetch32[2] += 3; rlm@1: rlm@1: prefetchActive = false; rlm@1: prefetchApplies = false; rlm@1: if (value & 0x4000) rlm@1: { rlm@1: for (i = 8; i < 16; i++) rlm@1: { rlm@1: memoryWaitFetch32[i] = 2 * cpuMemoryWait[i]; rlm@1: memoryWaitFetch[i] = cpuMemoryWait[i]; rlm@1: } rlm@1: if (((value & 3) == 3)) rlm@1: { rlm@1: if (!memLagTempEnabled) rlm@1: { rlm@1: memoryWaitFetch[8]--; // hack to prevent inaccurately extreme lag at some points of many games (possibly rlm@1: // from no pre-fetch emulation) rlm@1: /// FIXME: how correct is this? Should it set the fetch to 0 or change fetch32 or rlm@1: // anything else? rlm@1: rlm@1: prefetchActive = true; rlm@1: } rlm@1: prefetchApplies = true; rlm@1: } rlm@1: } rlm@1: //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600); rlm@1: //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600); rlm@1: prefetchPrevActive = prefetchActive; rlm@1: rlm@1: UPDATE_REG(0x204, value); rlm@1: break; rlm@1: } rlm@1: case 0x208: rlm@1: IME = value & 1; rlm@1: UPDATE_REG(0x208, IME); rlm@1: if ((IME & 1) && (IF & IE) && armIrqEnable) rlm@1: { rlm@1: CPU_BREAK_LOOP_2; rlm@1: } rlm@1: break; rlm@1: case 0x300: rlm@1: if (value != 0) rlm@1: value &= 0xFFFE; rlm@1: UPDATE_REG(0x300, value); rlm@1: break; rlm@1: default: rlm@1: UPDATE_REG(address & 0x3FE, value); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUWriteHalfWordWrapped(u32 address, u16 value) rlm@1: { rlm@1: #ifdef GBA_LOGGING rlm@1: if (address & 1) rlm@1: { rlm@1: if (systemVerbose & VERBOSE_UNALIGNED_MEMORY) rlm@1: { rlm@1: log("Unaligned halfword write: %04x to %08x from %08x\n", rlm@1: value, rlm@1: address, rlm@1: armMode ? armNextPC - 4 : armNextPC - 2); rlm@1: } rlm@1: } rlm@1: #endif rlm@1: rlm@1: switch (address >> 24) rlm@1: { rlm@1: case 2: rlm@1: #ifdef SDL rlm@1: if (*((u16 *)&freezeWorkRAM[address & 0x3FFFE])) rlm@1: cheatsWriteHalfWord((u16 *)&workRAM[address & 0x3FFFE], rlm@1: value, rlm@1: *((u16 *)&freezeWorkRAM[address & 0x3FFFE])); rlm@1: else rlm@1: #endif rlm@1: WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]), value); rlm@1: break; rlm@1: case 3: rlm@1: #ifdef SDL rlm@1: if (*((u16 *)&freezeInternalRAM[address & 0x7ffe])) rlm@1: cheatsWriteHalfWord((u16 *)&internalRAM[address & 0x7ffe], rlm@1: value, rlm@1: *((u16 *)&freezeInternalRAM[address & 0x7ffe])); rlm@1: else rlm@1: #endif rlm@1: WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value); rlm@1: break; rlm@1: case 4: rlm@1: CPUUpdateRegister(address & 0x3fe, value); rlm@1: break; rlm@1: case 5: rlm@1: WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value); rlm@1: break; rlm@1: case 6: rlm@1: if (address & 0x10000) rlm@1: WRITE16LE(((u16 *)&vram[address & 0x17ffe]), value); rlm@1: else rlm@1: WRITE16LE(((u16 *)&vram[address & 0x1fffe]), value); rlm@1: break; rlm@1: case 7: rlm@1: WRITE16LE(((u16 *)&oam[address & 0x3fe]), value); rlm@1: break; rlm@1: case 8: rlm@1: case 9: rlm@1: if (address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) rlm@1: { rlm@1: if (!rtcWrite(address, value)) rlm@1: goto unwritable; rlm@1: } rlm@1: else if (!agbPrintWrite(address, value)) rlm@1: goto unwritable; rlm@1: break; rlm@1: case 13: rlm@1: if (cpuEEPROMEnabled) rlm@1: { rlm@1: eepromWrite(address, (u8)(value & 0xFF)); rlm@1: break; rlm@1: } rlm@1: goto unwritable; rlm@1: case 14: rlm@1: if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled) rlm@1: { rlm@1: (*cpuSaveGameFunc)(address, (u8)(value & 0xFF)); rlm@1: break; rlm@1: } rlm@1: goto unwritable; rlm@1: default: rlm@1: unwritable: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_ILLEGAL_WRITE) rlm@1: { rlm@1: log("Illegal halfword write: %04x to %08x from %08x\n", rlm@1: value, rlm@1: address, rlm@1: armMode ? armNextPC - 4 : armNextPC - 2); rlm@1: } rlm@1: #endif rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUWriteHalfWord(u32 address, u16 value) rlm@1: { rlm@1: CPUWriteHalfWordWrapped(address, value); rlm@1: CallRegisteredLuaMemHook(address, 2, value, LUAMEMHOOK_WRITE); rlm@1: } rlm@1: rlm@1: void CPUWriteByteWrapped(u32 address, u8 b) rlm@1: { rlm@1: switch (address >> 24) rlm@1: { rlm@1: case 2: rlm@1: #ifdef SDL rlm@1: if (freezeWorkRAM[address & 0x3FFFF]) rlm@1: cheatsWriteByte(&workRAM[address & 0x3FFFF], b); rlm@1: else rlm@1: #endif rlm@1: workRAM[address & 0x3FFFF] = b; rlm@1: break; rlm@1: case 3: rlm@1: #ifdef SDL rlm@1: if (freezeInternalRAM[address & 0x7fff]) rlm@1: cheatsWriteByte(&internalRAM[address & 0x7fff], b); rlm@1: else rlm@1: #endif rlm@1: internalRAM[address & 0x7fff] = b; rlm@1: break; rlm@1: case 4: rlm@1: switch (address & 0x3FF) rlm@1: { rlm@1: case 0x301: rlm@1: if (b == 0x80) rlm@1: stopState = true; rlm@1: holdState = 1; rlm@1: holdType = -1; rlm@1: break; rlm@1: case 0x60: rlm@1: case 0x61: rlm@1: case 0x62: rlm@1: case 0x63: rlm@1: case 0x64: rlm@1: case 0x65: rlm@1: case 0x68: rlm@1: case 0x69: rlm@1: case 0x6c: rlm@1: case 0x6d: rlm@1: case 0x70: rlm@1: case 0x71: rlm@1: case 0x72: rlm@1: case 0x73: rlm@1: case 0x74: rlm@1: case 0x75: rlm@1: case 0x78: rlm@1: case 0x79: rlm@1: case 0x7c: rlm@1: case 0x7d: rlm@1: case 0x80: rlm@1: case 0x81: rlm@1: case 0x84: rlm@1: case 0x85: rlm@1: case 0x90: rlm@1: case 0x91: rlm@1: case 0x92: rlm@1: case 0x93: rlm@1: case 0x94: rlm@1: case 0x95: rlm@1: case 0x96: rlm@1: case 0x97: rlm@1: case 0x98: rlm@1: case 0x99: rlm@1: case 0x9a: rlm@1: case 0x9b: rlm@1: case 0x9c: rlm@1: case 0x9d: rlm@1: case 0x9e: rlm@1: case 0x9f: rlm@1: soundEvent(address & 0xFF, b); rlm@1: break; rlm@1: default: rlm@1: // if(address & 1) { rlm@1: // CPUWriteHalfWord(address-1, (CPUReadHalfWord(address-1)&0x00FF)|((int)b<<8)); rlm@1: // } else rlm@1: if (address & 1) rlm@1: CPUUpdateRegister(address & 0x3fe, rlm@1: ((READ16LE(((u16 *)&ioMem[address & 0x3fe]))) rlm@1: & 0x00FF) | rlm@1: b << 8); rlm@1: else rlm@1: CPUUpdateRegister(address & 0x3fe, rlm@1: ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b)); rlm@1: } rlm@1: break; rlm@1: case 5: rlm@1: // no need to switch rlm@1: *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b; rlm@1: break; rlm@1: case 6: rlm@1: // no need to switch rlm@1: if (address & 0x10000) rlm@1: *((u16 *)&vram[address & 0x17FFE]) = (b << 8) | b; rlm@1: else rlm@1: *((u16 *)&vram[address & 0x1FFFE]) = (b << 8) | b; rlm@1: break; rlm@1: case 7: rlm@1: // no need to switch rlm@1: *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b; rlm@1: break; rlm@1: case 13: rlm@1: if (cpuEEPROMEnabled) rlm@1: { rlm@1: eepromWrite(address, b); rlm@1: break; rlm@1: } rlm@1: goto unwritable; rlm@1: case 14: rlm@1: if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled) rlm@1: { rlm@1: (*cpuSaveGameFunc)(address, b); rlm@1: break; rlm@1: } rlm@1: // default rlm@1: default: rlm@1: unwritable: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_ILLEGAL_WRITE) rlm@1: { rlm@1: log("Illegal byte write: %02x to %08x from %08x\n", rlm@1: b, rlm@1: address, rlm@1: armMode ? armNextPC - 4 : armNextPC - 2); rlm@1: } rlm@1: #endif rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUWriteByte(u32 address, u8 b) rlm@1: { rlm@1: CPUWriteByteWrapped(address, b); rlm@1: CallRegisteredLuaMemHook(address, 1, b, LUAMEMHOOK_WRITE); rlm@1: } rlm@1: rlm@1: bool CPULoadBios(const char *biosFileName, bool useBiosFile) rlm@1: { rlm@1: useBios = false; rlm@1: if (useBiosFile) rlm@1: { rlm@1: useBios = utilLoadBIOS(bios, biosFileName, 4); rlm@1: if (!useBios) rlm@1: { rlm@1: systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid GBA BIOS file")); rlm@1: } rlm@1: } rlm@1: rlm@1: if (!useBios) rlm@1: { rlm@1: // load internal BIOS rlm@1: memcpy(bios, myROM, sizeof(myROM)); rlm@1: } rlm@1: rlm@1: return useBios; rlm@1: } rlm@1: rlm@1: void CPUInit() rlm@1: { rlm@1: #ifdef WORDS_BIGENDIAN rlm@1: if (!cpuBiosSwapped) rlm@1: { rlm@1: for (unsigned int i = 0; i < sizeof(myROM) / 4; i++) rlm@1: { rlm@1: WRITE32LE(&myROM[i], myROM[i]); rlm@1: } rlm@1: cpuBiosSwapped = true; rlm@1: } rlm@1: #endif rlm@1: gbaSaveType = 0; rlm@1: eepromInUse = 0; rlm@1: saveType = 0; rlm@1: rlm@1: if (!useBios) rlm@1: { rlm@1: // load internal BIOS rlm@1: memcpy(bios, myROM, sizeof(myROM)); rlm@1: } rlm@1: rlm@1: biosProtected[0] = 0x00; rlm@1: biosProtected[1] = 0xf0; rlm@1: biosProtected[2] = 0x29; rlm@1: biosProtected[3] = 0xe1; rlm@1: rlm@1: int i = 0; rlm@1: for (i = 0; i < 256; i++) rlm@1: { rlm@1: int cpuBitSetCount = 0; rlm@1: int j; rlm@1: for (j = 0; j < 8; j++) rlm@1: if (i & (1 << j)) rlm@1: cpuBitSetCount++; rlm@1: cpuBitsSet[i] = cpuBitSetCount; rlm@1: rlm@1: for (j = 0; j < 8; j++) rlm@1: if (i & (1 << j)) rlm@1: break; rlm@1: cpuLowestBitSet[i] = j; rlm@1: } rlm@1: rlm@1: for (i = 0; i < 0x400; i++) rlm@1: ioReadable[i] = true; rlm@1: for (i = 0x10; i < 0x48; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x4c; i < 0x50; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x54; i < 0x60; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x8c; i < 0x90; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0xa0; i < 0xb8; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0xbc; i < 0xc4; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0xc8; i < 0xd0; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0xd4; i < 0xdc; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0xe0; i < 0x100; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x110; i < 0x120; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x12c; i < 0x130; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x138; i < 0x140; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x144; i < 0x150; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x15c; i < 0x200; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x20c; i < 0x300; i++) rlm@1: ioReadable[i] = false; rlm@1: for (i = 0x304; i < 0x400; i++) rlm@1: ioReadable[i] = false; rlm@1: rlm@1: *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA rlm@1: *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR rlm@1: rlm@1: { rlm@1: int32 origMemoryWaitFetch[16] = { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; rlm@1: int32 origMemoryWaitFetch32[16] = { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 }; rlm@1: memcpy(memoryWaitFetch, origMemoryWaitFetch, 16 * sizeof(int32)); rlm@1: memcpy(memoryWaitFetch32, origMemoryWaitFetch32, 16 * sizeof(int32)); rlm@1: } rlm@1: } rlm@1: rlm@1: void CPUReset(bool userReset) rlm@1: { rlm@1: // movie must be closed while opening/creating a movie rlm@1: if (userReset && VBAMovieRecording()) rlm@1: { rlm@1: VBAMovieSignalReset(); rlm@1: return; rlm@1: } rlm@1: rlm@1: if (!VBAMovieActive()) rlm@1: { rlm@1: GBASystemCounters.frameCount = 0; rlm@1: GBASystemCounters.lagCount = 0; rlm@1: GBASystemCounters.extraCount = 0; rlm@1: GBASystemCounters.lagged = true; rlm@1: GBASystemCounters.laggedLast = true; rlm@1: } rlm@1: rlm@1: if (gbaSaveType == 0) rlm@1: { rlm@1: if (eepromInUse) rlm@1: gbaSaveType = 3; rlm@1: else rlm@1: switch (saveType) rlm@1: { rlm@1: case 1: rlm@1: gbaSaveType = 1; rlm@1: break; rlm@1: case 2: rlm@1: gbaSaveType = 2; rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: rtcReset(); rlm@1: // clean registers rlm@1: memset(®[0], 0, sizeof(reg)); rlm@1: // clean OAM rlm@1: memset(oam, 0, 0x400); rlm@1: // clean palette rlm@1: memset(paletteRAM, 0, 0x400); rlm@1: // clean picture rlm@1: memset(pix, 0, 4 * 241 * 162); rlm@1: // clean vram rlm@1: memset(vram, 0, 0x20000); rlm@1: // clean io memory rlm@1: memset(ioMem, 0, 0x400); rlm@1: // clean RAM rlm@1: memset(internalRAM, 0, 0x8000); /// FIXME: is it unsafe to erase ALL of this? Even the init code doesn't. rlm@1: memset(workRAM, 0, 0x40000); /// ditto rlm@1: rlm@1: DISPCNT = 0x0080; rlm@1: DISPSTAT = 0x0000; rlm@1: VCOUNT = 0x0000; rlm@1: BG0CNT = 0x0000; rlm@1: BG1CNT = 0x0000; rlm@1: BG2CNT = 0x0000; rlm@1: BG3CNT = 0x0000; rlm@1: BG0HOFS = 0x0000; rlm@1: BG0VOFS = 0x0000; rlm@1: BG1HOFS = 0x0000; rlm@1: BG1VOFS = 0x0000; rlm@1: BG2HOFS = 0x0000; rlm@1: BG2VOFS = 0x0000; rlm@1: BG3HOFS = 0x0000; rlm@1: BG3VOFS = 0x0000; rlm@1: BG2PA = 0x0100; rlm@1: BG2PB = 0x0000; rlm@1: BG2PC = 0x0000; rlm@1: BG2PD = 0x0100; rlm@1: BG2X_L = 0x0000; rlm@1: BG2X_H = 0x0000; rlm@1: BG2Y_L = 0x0000; rlm@1: BG2Y_H = 0x0000; rlm@1: BG3PA = 0x0100; rlm@1: BG3PB = 0x0000; rlm@1: BG3PC = 0x0000; rlm@1: BG3PD = 0x0100; rlm@1: BG3X_L = 0x0000; rlm@1: BG3X_H = 0x0000; rlm@1: BG3Y_L = 0x0000; rlm@1: BG3Y_H = 0x0000; rlm@1: WIN0H = 0x0000; rlm@1: WIN1H = 0x0000; rlm@1: WIN0V = 0x0000; rlm@1: WIN1V = 0x0000; rlm@1: WININ = 0x0000; rlm@1: WINOUT = 0x0000; rlm@1: MOSAIC = 0x0000; rlm@1: BLDMOD = 0x0000; rlm@1: COLEV = 0x0000; rlm@1: COLY = 0x0000; rlm@1: DM0SAD_L = 0x0000; rlm@1: DM0SAD_H = 0x0000; rlm@1: DM0DAD_L = 0x0000; rlm@1: DM0DAD_H = 0x0000; rlm@1: DM0CNT_L = 0x0000; rlm@1: DM0CNT_H = 0x0000; rlm@1: DM1SAD_L = 0x0000; rlm@1: DM1SAD_H = 0x0000; rlm@1: DM1DAD_L = 0x0000; rlm@1: DM1DAD_H = 0x0000; rlm@1: DM1CNT_L = 0x0000; rlm@1: DM1CNT_H = 0x0000; rlm@1: DM2SAD_L = 0x0000; rlm@1: DM2SAD_H = 0x0000; rlm@1: DM2DAD_L = 0x0000; rlm@1: DM2DAD_H = 0x0000; rlm@1: DM2CNT_L = 0x0000; rlm@1: DM2CNT_H = 0x0000; rlm@1: DM3SAD_L = 0x0000; rlm@1: DM3SAD_H = 0x0000; rlm@1: DM3DAD_L = 0x0000; rlm@1: DM3DAD_H = 0x0000; rlm@1: DM3CNT_L = 0x0000; rlm@1: DM3CNT_H = 0x0000; rlm@1: TM0D = 0x0000; rlm@1: TM0CNT = 0x0000; rlm@1: TM1D = 0x0000; rlm@1: TM1CNT = 0x0000; rlm@1: TM2D = 0x0000; rlm@1: TM2CNT = 0x0000; rlm@1: TM3D = 0x0000; rlm@1: TM3CNT = 0x0000; rlm@1: P1 = 0x03FF; rlm@1: IE = 0x0000; rlm@1: IF = 0x0000; rlm@1: IME = 0x0000; rlm@1: rlm@1: armMode = 0x1F; rlm@1: rlm@1: if (cpuIsMultiBoot) rlm@1: { rlm@1: reg[13].I = 0x03007F00; rlm@1: reg[15].I = 0x02000000; rlm@1: reg[16].I = 0x00000000; rlm@1: reg[R13_IRQ].I = 0x03007FA0; rlm@1: reg[R13_SVC].I = 0x03007FE0; rlm@1: armIrqEnable = true; rlm@1: } rlm@1: else rlm@1: { rlm@1: if (useBios && !skipBios) rlm@1: { rlm@1: reg[15].I = 0x00000000; rlm@1: armMode = 0x13; rlm@1: armIrqEnable = false; rlm@1: } rlm@1: else rlm@1: { rlm@1: reg[13].I = 0x03007F00; rlm@1: reg[15].I = 0x08000000; rlm@1: reg[16].I = 0x00000000; rlm@1: reg[R13_IRQ].I = 0x03007FA0; rlm@1: reg[R13_SVC].I = 0x03007FE0; rlm@1: armIrqEnable = true; rlm@1: } rlm@1: } rlm@1: armState = true; rlm@1: C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; rlm@1: UPDATE_REG(0x00, DISPCNT); rlm@1: UPDATE_REG(0x20, BG2PA); rlm@1: UPDATE_REG(0x26, BG2PD); rlm@1: UPDATE_REG(0x30, BG3PA); rlm@1: UPDATE_REG(0x36, BG3PD); rlm@1: UPDATE_REG(0x130, P1); rlm@1: UPDATE_REG(0x88, 0x200); rlm@1: rlm@1: // disable FIQ rlm@1: reg[16].I |= 0x40; rlm@1: CPUUpdateCPSR(); rlm@1: rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 4; rlm@1: rlm@1: // reset internal state rlm@1: holdState = false; rlm@1: holdType = 0; rlm@1: rlm@1: biosProtected[0] = 0x00; rlm@1: biosProtected[1] = 0xf0; rlm@1: biosProtected[2] = 0x29; rlm@1: biosProtected[3] = 0xe1; rlm@1: rlm@1: BIOS_RegisterRamReset(); rlm@1: rlm@1: lcdTicks = 960; rlm@1: timer0On = false; rlm@1: timer0Ticks = 0; rlm@1: timer0Reload = 0; rlm@1: timer0ClockReload = 0; rlm@1: timer1On = false; rlm@1: timer1Ticks = 0; rlm@1: timer1Reload = 0; rlm@1: timer1ClockReload = 0; rlm@1: timer2On = false; rlm@1: timer2Ticks = 0; rlm@1: timer2Reload = 0; rlm@1: timer2ClockReload = 0; rlm@1: timer3On = false; rlm@1: timer3Ticks = 0; rlm@1: timer3Reload = 0; rlm@1: timer3ClockReload = 0; rlm@1: dma0Source = 0; rlm@1: dma0Dest = 0; rlm@1: dma1Source = 0; rlm@1: dma1Dest = 0; rlm@1: dma2Source = 0; rlm@1: dma2Dest = 0; rlm@1: dma3Source = 0; rlm@1: dma3Dest = 0; rlm@1: cpuSaveGameFunc = flashSaveDecide; rlm@1: renderLine = mode0RenderLine; rlm@1: fxOn = false; rlm@1: windowOn = false; rlm@1: frameSkipCount = 0; rlm@1: saveType = 0; rlm@1: layerEnable = DISPCNT & layerSettings; rlm@1: rlm@1: CPUUpdateRenderBuffers(true); rlm@1: rlm@1: for (int i = 0; i < 256; i++) rlm@1: { rlm@1: map[i].address = (u8 *)&dummyAddress; rlm@1: map[i].mask = 0; rlm@1: } rlm@1: rlm@1: map[0].address = bios; rlm@1: map[0].mask = 0x3FFF; rlm@1: map[2].address = workRAM; rlm@1: map[2].mask = 0x3FFFF; rlm@1: map[3].address = internalRAM; rlm@1: map[3].mask = 0x7FFF; rlm@1: map[4].address = ioMem; rlm@1: map[4].mask = 0x3FF; rlm@1: map[5].address = paletteRAM; rlm@1: map[5].mask = 0x3FF; rlm@1: map[6].address = vram; rlm@1: map[6].mask = 0x1FFFF; rlm@1: map[7].address = oam; rlm@1: map[7].mask = 0x3FF; rlm@1: map[8].address = rom; rlm@1: map[8].mask = 0x1FFFFFF; rlm@1: map[9].address = rom; rlm@1: map[9].mask = 0x1FFFFFF; rlm@1: map[10].address = rom; rlm@1: map[10].mask = 0x1FFFFFF; rlm@1: map[12].address = rom; rlm@1: map[12].mask = 0x1FFFFFF; rlm@1: map[14].address = flashSaveMemory; rlm@1: map[14].mask = 0xFFFF; rlm@1: rlm@1: eepromReset(); rlm@1: flashReset(); rlm@1: rlm@1: soundReset(); rlm@1: rlm@1: CPUUpdateWindow0(); rlm@1: CPUUpdateWindow1(); rlm@1: rlm@1: // make sure registers are correctly initialized if not using BIOS rlm@1: if (!useBios) rlm@1: { rlm@1: if (cpuIsMultiBoot) rlm@1: BIOS_RegisterRamReset(0xfe); rlm@1: else rlm@1: BIOS_RegisterRamReset(0xff); rlm@1: } rlm@1: else rlm@1: { rlm@1: if (cpuIsMultiBoot) rlm@1: BIOS_RegisterRamReset(0xfe); rlm@1: } rlm@1: rlm@1: switch (cpuSaveType) rlm@1: { rlm@1: case 0: // automatic rlm@1: cpuSramEnabled = true; rlm@1: cpuFlashEnabled = true; rlm@1: cpuEEPROMEnabled = true; rlm@1: cpuEEPROMSensorEnabled = false; rlm@1: break; rlm@1: case 1: // EEPROM rlm@1: cpuSramEnabled = false; rlm@1: cpuFlashEnabled = false; rlm@1: cpuEEPROMEnabled = true; rlm@1: cpuEEPROMSensorEnabled = false; rlm@1: break; rlm@1: case 2: // SRAM rlm@1: cpuSramEnabled = true; rlm@1: cpuFlashEnabled = false; rlm@1: cpuEEPROMEnabled = false; rlm@1: cpuEEPROMSensorEnabled = false; rlm@1: cpuSaveGameFunc = sramWrite; rlm@1: break; rlm@1: case 3: // FLASH rlm@1: cpuSramEnabled = false; rlm@1: cpuFlashEnabled = true; rlm@1: cpuEEPROMEnabled = false; rlm@1: cpuEEPROMSensorEnabled = false; rlm@1: cpuSaveGameFunc = flashWrite; rlm@1: break; rlm@1: case 4: // EEPROM+Sensor rlm@1: cpuSramEnabled = false; rlm@1: cpuFlashEnabled = false; rlm@1: cpuEEPROMEnabled = true; rlm@1: cpuEEPROMSensorEnabled = true; rlm@1: break; rlm@1: case 5: // NONE rlm@1: cpuSramEnabled = false; rlm@1: cpuFlashEnabled = false; rlm@1: cpuEEPROMEnabled = false; rlm@1: cpuEEPROMSensorEnabled = false; rlm@1: break; rlm@1: } rlm@1: rlm@1: systemResetSensor(); rlm@1: rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; rlm@1: rlm@1: gbaLastTime = systemGetClock(); rlm@1: gbaFrameCount = 0; rlm@1: rlm@1: systemRefreshScreen(); rlm@1: } rlm@1: rlm@1: void CPUInterrupt() rlm@1: { rlm@1: u32 PC = reg[15].I; rlm@1: bool savedState = armState; rlm@1: CPUSwitchMode(0x12, true, false); rlm@1: reg[14].I = PC; rlm@1: if (!savedState) rlm@1: reg[14].I += 2; rlm@1: reg[15].I = 0x18; rlm@1: armState = true; rlm@1: armIrqEnable = false; rlm@1: rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 4; rlm@1: rlm@1: // if(!holdState) rlm@1: biosProtected[0] = 0x02; rlm@1: biosProtected[1] = 0xc0; rlm@1: biosProtected[2] = 0x5e; rlm@1: biosProtected[3] = 0xe5; rlm@1: } rlm@1: rlm@1: void TogglePrefetchHack() rlm@1: { rlm@1: memLagTempEnabled = !memLagTempEnabled; rlm@1: rlm@1: if (emulating) rlm@1: { rlm@1: extern bool8 prefetchActive, prefetchPrevActive, prefetchApplies; rlm@1: if (prefetchApplies && prefetchActive == memLagTempEnabled) rlm@1: { rlm@1: prefetchActive = !prefetchActive; rlm@1: //if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600); rlm@1: //if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600); rlm@1: extern int32 memoryWaitFetch [16]; rlm@1: if (prefetchActive) rlm@1: memoryWaitFetch[8]--; rlm@1: else rlm@1: memoryWaitFetch[8]++; rlm@1: prefetchPrevActive = prefetchActive; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void SetPrefetchHack(bool set) rlm@1: { rlm@1: if ((bool)memLagTempEnabled == set) rlm@1: TogglePrefetchHack(); rlm@1: } rlm@1: rlm@1: #ifdef SDL rlm@1: void log(const char *defaultMsg, ...) rlm@1: { rlm@1: char buffer[2048]; rlm@1: va_list valist; rlm@1: rlm@1: va_start(valist, defaultMsg); rlm@1: vsprintf(buffer, defaultMsg, valist); rlm@1: rlm@1: if (out == NULL) rlm@1: { rlm@1: out = fopen("trace.log", "w"); rlm@1: } rlm@1: rlm@1: fputs(buffer, out); rlm@1: rlm@1: va_end(valist); rlm@1: } rlm@1: rlm@1: #else rlm@1: extern void winlog(const char *, ...); rlm@1: #endif rlm@1: rlm@92: void CPULoop2(int _ticks) rlm@1: { rlm@1: int32 ticks = _ticks; rlm@1: int32 clockTicks; rlm@1: int32 cpuLoopTicks = 0; rlm@1: int32 timerOverflow = 0; rlm@1: // variables used by the CPU core rlm@1: rlm@1: extCpuLoopTicks = &cpuLoopTicks; rlm@1: extClockTicks = &clockTicks; rlm@1: extTicks = &ticks; rlm@1: rlm@1: cpuLoopTicks = CPUUpdateTicks(); rlm@1: if (cpuLoopTicks > ticks) rlm@1: { rlm@1: cpuLoopTicks = ticks; rlm@1: cpuSavedTicks = ticks; rlm@1: } rlm@1: rlm@1: if (intState) rlm@1: { rlm@1: cpuLoopTicks = 5; rlm@1: cpuSavedTicks = 5; rlm@1: } rlm@1: rlm@1: if (newFrame) rlm@1: { rlm@1: extern void VBAOnExitingFrameBoundary(); rlm@1: VBAOnExitingFrameBoundary(); rlm@1: rlm@1: // update joystick information rlm@1: systemReadJoypads(); rlm@1: rlm@1: u32 joy = systemGetJoypad(0, cpuEEPROMSensorEnabled); rlm@1: rlm@1: // if (cpuEEPROMSensorEnabled) rlm@1: // systemUpdateMotionSensor(0); rlm@1: rlm@1: P1 = 0x03FF ^ (joy & 0x3FF); rlm@1: UPDATE_REG(0x130, P1); rlm@1: u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132])); rlm@1: // this seems wrong, but there are cases where the game rlm@1: // can enter the stop state without requesting an IRQ from rlm@1: // the joypad. rlm@1: if ((P1CNT & 0x4000) || stopState) rlm@1: { rlm@1: u16 p1 = (0x3FF ^ P1) & 0x3FF; rlm@1: if (P1CNT & 0x8000) rlm@1: { rlm@1: if (p1 == (P1CNT & 0x3FF)) rlm@1: { rlm@1: IF |= 0x1000; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (p1 & P1CNT) rlm@1: { rlm@1: IF |= 0x1000; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: // HACK: some special "buttons" rlm@1: extButtons = (joy >> 18); rlm@1: speedup = (extButtons & 1) != 0; rlm@1: rlm@1: VBAMovieResetIfRequested(); rlm@1: rlm@1: CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); rlm@1: rlm@1: newFrame = false; rlm@1: } rlm@1: rlm@1: for (;; ) rlm@1: { rlm@1: #ifndef FINAL_VERSION rlm@1: if (systemDebug) rlm@1: { rlm@1: if (systemDebug >= 10 && !holdState) rlm@1: { rlm@1: CPUUpdateCPSR(); rlm@1: sprintf( rlm@1: buffer, rlm@1: "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x" rlm@1: "R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", rlm@1: reg[0].I, rlm@1: reg[1].I, rlm@1: reg[2].I, rlm@1: reg[3].I, rlm@1: reg[4].I, rlm@1: reg[5].I, rlm@1: reg[6].I, rlm@1: reg[7].I, rlm@1: reg[8].I, rlm@1: reg[9].I, rlm@1: reg[10].I, rlm@1: reg[11].I, rlm@1: reg[12].I, rlm@1: reg[13].I, rlm@1: reg[14].I, rlm@1: reg[15].I, rlm@1: reg[16].I, rlm@1: reg[17].I); rlm@1: #ifdef SDL rlm@1: log(buffer); rlm@1: #else rlm@1: winlog(buffer); rlm@1: #endif rlm@1: } rlm@1: else if (!holdState) rlm@1: { rlm@1: sprintf(buffer, "PC=%08x\n", armNextPC); rlm@1: #ifdef SDL rlm@1: log(buffer); rlm@1: #else rlm@1: winlog(buffer); rlm@1: #endif rlm@1: } rlm@1: } rlm@1: #endif rlm@1: rlm@1: if (!holdState) rlm@1: { rlm@1: if (armState) rlm@1: { rlm@1: CallRegisteredLuaMemHook(armNextPC, 4, CPUReadMemoryQuick(armNextPC), LUAMEMHOOK_EXEC); rlm@1: #include "arm-new.h" rlm@1: } rlm@1: else rlm@1: { rlm@1: CallRegisteredLuaMemHook(armNextPC, 2, CPUReadHalfWordQuick(armNextPC), LUAMEMHOOK_EXEC); rlm@1: #include "thumb.h" rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: clockTicks = lcdTicks; rlm@1: rlm@1: if (soundTicks < clockTicks) rlm@1: clockTicks = soundTicks; rlm@1: rlm@1: if (timer0On && (timer0Ticks < clockTicks)) rlm@1: { rlm@1: clockTicks = timer0Ticks; rlm@1: } rlm@1: if (timer1On && (timer1Ticks < clockTicks)) rlm@1: { rlm@1: clockTicks = timer1Ticks; rlm@1: } rlm@1: if (timer2On && (timer2Ticks < clockTicks)) rlm@1: { rlm@1: clockTicks = timer2Ticks; rlm@1: } rlm@1: if (timer3On && (timer3Ticks < clockTicks)) rlm@1: { rlm@1: clockTicks = timer3Ticks; rlm@1: } rlm@1: #ifdef PROFILING rlm@1: if (profilingTicksReload != 0) rlm@1: { rlm@1: if (profilingTicks < clockTicks) rlm@1: { rlm@1: clockTicks = profilingTicks; rlm@1: } rlm@1: } rlm@1: #endif rlm@1: } rlm@1: rlm@1: cpuLoopTicks -= clockTicks; rlm@1: if ((cpuLoopTicks <= 0)) rlm@1: { rlm@1: if (cpuSavedTicks) rlm@1: { rlm@1: clockTicks = cpuSavedTicks; // + cpuLoopTicks; rlm@1: } rlm@1: cpuDmaTicksToUpdate = -cpuLoopTicks; rlm@1: rlm@1: updateLoop: rlm@1: lcdTicks -= clockTicks; rlm@1: rlm@1: if (lcdTicks <= 0) rlm@1: { rlm@1: if (DISPSTAT & 1) // V-BLANK rlm@1: { // if in V-Blank mode, keep computing... rlm@1: if (DISPSTAT & 2) rlm@1: { rlm@1: lcdTicks += 960; rlm@1: VCOUNT++; rlm@1: UPDATE_REG(0x06, VCOUNT); rlm@1: DISPSTAT &= 0xFFFD; rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: CPUCompareVCOUNT(); rlm@1: } rlm@1: else rlm@1: { rlm@1: lcdTicks += 272; rlm@1: DISPSTAT |= 2; rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: if (DISPSTAT & 16) rlm@1: { rlm@1: IF |= 2; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: rlm@1: if (VCOUNT >= 228) rlm@1: { rlm@1: DISPSTAT &= 0xFFFC; rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: VCOUNT = 0; rlm@1: UPDATE_REG(0x06, VCOUNT); rlm@1: CPUCompareVCOUNT(); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: int framesToSkip = systemFramesToSkip(); rlm@1: rlm@1: if (DISPSTAT & 2) rlm@1: { rlm@1: // if in H-Blank, leave it and move to drawing mode rlm@1: VCOUNT++; rlm@1: UPDATE_REG(0x06, VCOUNT); rlm@1: rlm@1: lcdTicks += 960; rlm@1: DISPSTAT &= 0xFFFD; rlm@1: if (VCOUNT == 160) rlm@1: { rlm@1: DISPSTAT |= 1; rlm@1: DISPSTAT &= 0xFFFD; rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: if (DISPSTAT & 0x0008) rlm@1: { rlm@1: IF |= 1; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: CPUCheckDMA(1, 0x0f); rlm@1: rlm@1: systemFrame(); rlm@1: rlm@1: ++gbaFrameCount; rlm@1: u32 gbaCurrentTime = systemGetClock(); rlm@1: if (gbaCurrentTime - gbaLastTime >= 1000) rlm@1: { rlm@1: systemShowSpeed(int(float(gbaFrameCount) * 100000 / (float(gbaCurrentTime - gbaLastTime) * 60) + .5f)); rlm@1: gbaLastTime = gbaCurrentTime; rlm@1: gbaFrameCount = 0; rlm@1: } rlm@1: rlm@1: ++GBASystemCounters.frameCount; rlm@1: if (GBASystemCounters.lagged) rlm@1: { rlm@1: ++GBASystemCounters.lagCount; rlm@1: } rlm@1: GBASystemCounters.laggedLast = GBASystemCounters.lagged; rlm@1: GBASystemCounters.lagged = true; rlm@1: rlm@1: if (cheatsEnabled) rlm@1: cheatsCheckKeys(P1 ^ 0x3FF, extButtons); rlm@1: rlm@1: extern void VBAOnEnteringFrameBoundary(); rlm@1: VBAOnEnteringFrameBoundary(); rlm@1: rlm@1: newFrame = true; rlm@1: rlm@1: pauseAfterFrameAdvance = systemPauseOnFrame(); rlm@1: rlm@1: if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance) rlm@1: { rlm@1: systemRenderFrame(); rlm@1: frameSkipCount = 0; rlm@1: rlm@1: bool capturePressed = (extButtons & 2) != 0; rlm@1: if (capturePressed && !capturePrevious) rlm@1: { rlm@1: captureNumber = systemScreenCapture(captureNumber); rlm@1: } rlm@1: capturePrevious = capturePressed && !pauseAfterFrameAdvance; rlm@1: } rlm@1: else rlm@1: { rlm@1: ++frameSkipCount; rlm@1: } rlm@1: rlm@1: if (pauseAfterFrameAdvance) rlm@1: { rlm@1: systemSetPause(true); rlm@1: } rlm@1: } rlm@1: rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: CPUCompareVCOUNT(); rlm@1: } rlm@1: else rlm@1: { rlm@1: if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance) rlm@1: { rlm@1: (*renderLine)(); rlm@1: rlm@1: switch (systemColorDepth) rlm@1: { rlm@1: case 16: rlm@1: { rlm@1: u16 *dest = (u16 *)pix + 242 * (VCOUNT + 1); rlm@1: for (int x = 0; x < 240; ) rlm@1: { rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap16[lineMix[x++] & 0xFFFF]; rlm@1: } rlm@1: // for filters that read past the screen rlm@1: *dest++ = 0; rlm@1: break; rlm@1: } rlm@1: case 24: rlm@1: { rlm@1: u8 *dest = (u8 *)pix + 240 * VCOUNT * 3; rlm@1: for (int x = 0; x < 240; ) rlm@1: { rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: dest += 3; rlm@1: } rlm@1: break; rlm@1: } rlm@1: case 32: rlm@1: { rlm@1: u32 *dest = (u32 *)pix + 241 * (VCOUNT + 1); rlm@1: for (int x = 0; x < 240; ) rlm@1: { rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: // entering H-Blank rlm@1: DISPSTAT |= 2; rlm@1: UPDATE_REG(0x04, DISPSTAT); rlm@1: lcdTicks += 272; rlm@1: CPUCheckDMA(2, 0x0f); rlm@1: if (DISPSTAT & 16) rlm@1: { rlm@1: IF |= 2; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: if (!stopState) rlm@1: { rlm@1: if (timer0On) rlm@1: { rlm@1: if (timer0ClockReload == 1) rlm@1: { rlm@1: u32 tm0d = TM0D + clockTicks; rlm@1: if (tm0d > 0xffff) rlm@1: { rlm@1: tm0d += timer0Reload; rlm@1: timerOverflow |= 1; rlm@1: soundTimerOverflow(0); rlm@1: if (TM0CNT & 0x40) rlm@1: { rlm@1: IF |= 0x08; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: TM0D = tm0d & 0xFFFF; rlm@1: timer0Ticks = 0x10000 - TM0D; rlm@1: UPDATE_REG(0x100, TM0D); rlm@1: } rlm@1: else rlm@1: { rlm@1: timer0Ticks -= clockTicks; rlm@1: if (timer0Ticks <= 0) rlm@1: { rlm@1: timer0Ticks += timer0ClockReload; rlm@1: TM0D++; rlm@1: if (TM0D == 0) rlm@1: { rlm@1: TM0D = timer0Reload; rlm@1: timerOverflow |= 1; rlm@1: soundTimerOverflow(0); rlm@1: if (TM0CNT & 0x40) rlm@1: { rlm@1: IF |= 0x08; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: UPDATE_REG(0x100, TM0D); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: if (timer1On) rlm@1: { rlm@1: if (TM1CNT & 4) rlm@1: { rlm@1: if (timerOverflow & 1) rlm@1: { rlm@1: TM1D++; rlm@1: if (TM1D == 0) rlm@1: { rlm@1: TM1D += timer1Reload; rlm@1: timerOverflow |= 2; rlm@1: soundTimerOverflow(1); rlm@1: if (TM1CNT & 0x40) rlm@1: { rlm@1: IF |= 0x10; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: UPDATE_REG(0x104, TM1D); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (timer1ClockReload == 1) rlm@1: { rlm@1: u32 tm1d = TM1D + clockTicks; rlm@1: if (tm1d > 0xffff) rlm@1: { rlm@1: tm1d += timer1Reload; rlm@1: timerOverflow |= 2; rlm@1: soundTimerOverflow(1); rlm@1: if (TM1CNT & 0x40) rlm@1: { rlm@1: IF |= 0x10; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: TM1D = tm1d & 0xFFFF; rlm@1: timer1Ticks = 0x10000 - TM1D; rlm@1: UPDATE_REG(0x104, TM1D); rlm@1: } rlm@1: else rlm@1: { rlm@1: timer1Ticks -= clockTicks; rlm@1: if (timer1Ticks <= 0) rlm@1: { rlm@1: timer1Ticks += timer1ClockReload; rlm@1: TM1D++; rlm@1: rlm@1: if (TM1D == 0) rlm@1: { rlm@1: TM1D = timer1Reload; rlm@1: timerOverflow |= 2; rlm@1: soundTimerOverflow(1); rlm@1: if (TM1CNT & 0x40) rlm@1: { rlm@1: IF |= 0x10; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: UPDATE_REG(0x104, TM1D); rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: if (timer2On) rlm@1: { rlm@1: if (TM2CNT & 4) rlm@1: { rlm@1: if (timerOverflow & 2) rlm@1: { rlm@1: TM2D++; rlm@1: if (TM2D == 0) rlm@1: { rlm@1: TM2D += timer2Reload; rlm@1: timerOverflow |= 4; rlm@1: if (TM2CNT & 0x40) rlm@1: { rlm@1: IF |= 0x20; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: UPDATE_REG(0x108, TM2D); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (timer2ClockReload == 1) rlm@1: { rlm@1: u32 tm2d = TM2D + clockTicks; rlm@1: if (tm2d > 0xffff) rlm@1: { rlm@1: tm2d += timer2Reload; rlm@1: timerOverflow |= 4; rlm@1: if (TM2CNT & 0x40) rlm@1: { rlm@1: IF |= 0x20; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: TM2D = tm2d & 0xFFFF; rlm@1: timer2Ticks = 0x10000 - TM2D; rlm@1: UPDATE_REG(0x108, TM2D); rlm@1: } rlm@1: else rlm@1: { rlm@1: timer2Ticks -= clockTicks; rlm@1: if (timer2Ticks <= 0) rlm@1: { rlm@1: timer2Ticks += timer2ClockReload; rlm@1: TM2D++; rlm@1: rlm@1: if (TM2D == 0) rlm@1: { rlm@1: TM2D = timer2Reload; rlm@1: timerOverflow |= 4; rlm@1: if (TM2CNT & 0x40) rlm@1: { rlm@1: IF |= 0x20; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: UPDATE_REG(0x108, TM2D); rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: if (timer3On) rlm@1: { rlm@1: if (TM3CNT & 4) rlm@1: { rlm@1: if (timerOverflow & 4) rlm@1: { rlm@1: TM3D++; rlm@1: if (TM3D == 0) rlm@1: { rlm@1: TM3D += timer3Reload; rlm@1: if (TM3CNT & 0x40) rlm@1: { rlm@1: IF |= 0x40; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: UPDATE_REG(0x10c, TM3D); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (timer3ClockReload == 1) rlm@1: { rlm@1: u32 tm3d = TM3D + clockTicks; rlm@1: if (tm3d > 0xffff) rlm@1: { rlm@1: tm3d += timer3Reload; rlm@1: if (TM3CNT & 0x40) rlm@1: { rlm@1: IF |= 0x40; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: TM3D = tm3d & 0xFFFF; rlm@1: timer3Ticks = 0x10000 - TM3D; rlm@1: UPDATE_REG(0x10C, TM3D); rlm@1: } rlm@1: else rlm@1: { rlm@1: timer3Ticks -= clockTicks; rlm@1: if (timer3Ticks <= 0) rlm@1: { rlm@1: timer3Ticks += timer3ClockReload; rlm@1: TM3D++; rlm@1: rlm@1: if (TM3D == 0) rlm@1: { rlm@1: TM3D = timer3Reload; rlm@1: if (TM3CNT & 0x40) rlm@1: { rlm@1: IF |= 0x40; rlm@1: UPDATE_REG(0x202, IF); rlm@1: } rlm@1: } rlm@1: UPDATE_REG(0x10C, TM3D); rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: // we shouldn't be doing sound in stop state, but we lose synchronization rlm@1: // if sound is disabled, so in stop state, soundTick will just produce rlm@1: // mute sound rlm@1: soundTicks -= clockTicks; rlm@1: if (soundTicks < 1) rlm@1: { rlm@1: soundTick(); rlm@1: soundTicks += SOUND_CLOCK_TICKS; rlm@1: } rlm@1: timerOverflow = 0; rlm@1: rlm@1: #ifdef PROFILING rlm@1: profilingTicks -= clockTicks; rlm@1: if (profilingTicks <= 0) rlm@1: { rlm@1: profilingTicks += profilingTicksReload; rlm@1: if (profilBuffer && profilSize) rlm@1: { rlm@1: u16 *b = (u16 *)profilBuffer; rlm@1: int pc = ((reg[15].I - profilLowPC) * profilScale) / 0x10000; rlm@1: if (pc >= 0 && pc < profilSize) rlm@1: { rlm@1: b[pc]++; rlm@1: } rlm@1: } rlm@1: } rlm@1: #endif rlm@1: rlm@1: ticks -= clockTicks; rlm@1: cpuLoopTicks = CPUUpdateTicks(); rlm@1: rlm@1: // FIXME: it is too bad that it is still not determined whether the loop can be exited at this point rlm@1: if (cpuDmaTicksToUpdate > 0) rlm@1: { rlm@1: clockTicks = cpuSavedTicks; rlm@1: if (clockTicks > cpuDmaTicksToUpdate) rlm@1: clockTicks = cpuDmaTicksToUpdate; rlm@1: cpuDmaTicksToUpdate -= clockTicks; rlm@1: if (cpuDmaTicksToUpdate < 0) rlm@1: cpuDmaTicksToUpdate = 0; rlm@1: goto updateLoop; // this is evil rlm@1: } rlm@1: rlm@1: if (IF && (IME & 1) && armIrqEnable) rlm@1: { rlm@1: int res = IF & IE; rlm@1: if (stopState) rlm@1: res &= 0x3080; rlm@1: if (res) rlm@1: { rlm@1: if (intState) rlm@1: { rlm@1: CPUInterrupt(); rlm@1: intState = false; rlm@1: if (holdState) rlm@1: { rlm@1: holdState = false; rlm@1: stopState = false; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (!holdState) rlm@1: { rlm@1: intState = true; rlm@1: cpuLoopTicks = 5; rlm@1: cpuSavedTicks = 5; rlm@1: } rlm@1: else rlm@1: { rlm@1: CPUInterrupt(); rlm@1: if (holdState) rlm@1: { rlm@1: holdState = false; rlm@1: stopState = false; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: if (useOldFrameTiming) rlm@1: { rlm@1: if (ticks <= 0) rlm@1: { rlm@1: newFrame = true; rlm@1: break; rlm@1: } rlm@1: } rlm@1: else if (newFrame) rlm@1: { rlm@1: // FIXME: it should be enough to use frameBoundary only if there were no need for supporting the old timing rlm@1: // but is there still any GBA .vbm that uses the old timing? rlm@1: /// extern void VBAOnEnteringFrameBoundary(); rlm@1: /// VBAOnEnteringFrameBoundary(); rlm@1: rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@92: rlm@92: // RLM: rlm@92: int CPULoop(int _ticks){ rlm@92: CPULoop2(_ticks); rlm@92: return 1; rlm@92: } rlm@92: rlm@92: rlm@1: struct EmulatedSystem GBASystem = rlm@1: { rlm@1: // emuMain rlm@1: CPULoop, rlm@1: // emuReset rlm@1: CPUReset, rlm@1: // emuCleanUp rlm@1: CPUCleanUp, rlm@1: // emuReadBattery rlm@1: CPUReadBatteryFile, rlm@1: // emuWriteBattery rlm@1: CPUWriteBatteryFile, rlm@1: // emuReadBatteryFromStream rlm@1: CPUReadBatteryFromStream, rlm@1: // emuWriteBatteryToStream rlm@1: CPUWriteBatteryToStream, rlm@1: // emuReadState rlm@1: CPUReadState, rlm@1: // emuWriteState rlm@1: CPUWriteState, rlm@1: // emuReadStateFromStream rlm@1: CPUReadStateFromStream, rlm@1: // emuWriteStateToStream rlm@1: CPUWriteStateToStream, rlm@1: // emuReadMemState rlm@1: CPUReadMemState, rlm@1: // emuWriteMemState rlm@1: CPUWriteMemState, rlm@1: // emuWritePNG rlm@1: CPUWritePNGFile, rlm@1: // emuWriteBMP rlm@1: CPUWriteBMPFile, rlm@1: // emuUpdateCPSR rlm@1: CPUUpdateCPSR, rlm@1: // emuHasDebugger rlm@1: true, rlm@1: // emuCount rlm@1: #ifdef FINAL_VERSION rlm@1: 250000, rlm@1: #else rlm@1: 5000, rlm@1: #endif rlm@1: }; rlm@1: rlm@1: // is there a reason to use more than one set of counters? rlm@1: EmulatedSystemCounters &GBASystemCounters = systemCounters; rlm@1: rlm@1: /* rlm@1: EmulatedSystemCounters GBASystemCounters = rlm@1: { rlm@1: // frameCount rlm@1: 0, rlm@1: // lagCount rlm@1: 0, rlm@1: // lagged rlm@1: true, rlm@1: // laggedLast rlm@1: true, rlm@1: }; rlm@1: */ rlm@1: rlm@1: rlm@1: #undef CPU_BREAK_LOOP rlm@1: #undef CPU_BREAK_LOOP2