home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / GBA.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  92.4 KB  |  3,955 lines

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