1 /*
2 	Copyright (C) 2006 yopyop
3 	Copyright (C) 2008-2015 DeSmuME team
4 
5 	This file 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 of the License, or
8 	(at your option) any later version.
9 
10 	This file 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 the this software.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "NDSSystem.h"
20 
21 #include <string.h>
22 #include <stdlib.h>
23 #include <algorithm>
24 #include <math.h>
25 
26 #include <string/stdstring.h>
27 extern unsigned long crc32(unsigned long, const unsigned char*,unsigned int);
28 
29 #include "utils/dlditool.h"
30 #include "utils/decrypt/decrypt.h"
31 #include "utils/decrypt/crc.h"
32 #include "utils/advanscene.h"
33 #include "utils/task.h"
34 #include "utils/bits.h"
35 
36 #include "common.h"
37 #include "armcpu.h"
38 #include "render3D.h"
39 #include "MMU.h"
40 #include "gfx3d.h"
41 #include "GPU.h"
42 #include "cp15.h"
43 #include "bios.h"
44 #include "debug.h"
45 #include "cheatSystem.h"
46 #include "movie.h"
47 #include "emufile.h"
48 #ifdef DEBUG
49 #include "Disassembler.h"
50 #endif
51 #include "FIFO.h"
52 #include "readwrite.h"
53 #include "registers.h"
54 #ifdef DEBUG
55 #include "debug.h"
56 #endif
57 #include "driver.h"
58 #include "firmware.h"
59 #include "version.h"
60 #include "path.h"
61 #include "slot1.h"
62 #include "slot2.h"
63 #include "SPU.h"
64 #include "wifi.h"
65 
66 
67 //int xxctr=0;
68 //#define LOG_ARM9
69 //#define LOG_ARM7
70 //#define dolog (currFrameCounter>30)
71 bool dolog = false;
72 //#define LOG_TO_FILE
73 //#define LOG_TO_FILE_REGS
74 
75 //===============================================================
76 FILE *fp_dis7 = NULL;
77 FILE *fp_dis9 = NULL;
78 
79 PathInfo path;
80 
81 TCommonSettings CommonSettings;
82 static BaseDriver _stub_driver;
83 BaseDriver* driver = &_stub_driver;
84 
85 static BOOL LidClosed = FALSE;
86 static u8	countLid = 0;
87 
88 GameInfo gameInfo;
89 NDSSystem nds;
90 CFIRMWARE	*firmware = NULL;
91 
92 using std::min;
93 using std::max;
94 
95 bool singleStep;
96 bool nds_debug_continuing[2];
97 
98 TSCalInfo TSCal;
99 
100 extern "C" int DLDI_tryPatch(void* data, size_t size, unsigned int device);
101 
Desmume_InitOnce()102 void Desmume_InitOnce()
103 {
104 	static bool initOnce = false;
105 	if(initOnce) return;
106 	initOnce = true;
107 }
108 
NDS_GetCPUCoreCount(void)109 int NDS_GetCPUCoreCount(void)
110 {
111    int amount = cpu_features_get_core_amount();
112    return amount;
113 }
114 
NDS_SetupDefaultFirmware()115 void NDS_SetupDefaultFirmware()
116 {
117 	NDS_FillDefaultFirmwareConfigData(&CommonSettings.fw_config);
118 }
119 
NDS_RunAdvansceneAutoImport()120 void NDS_RunAdvansceneAutoImport()
121 {
122 	if(CommonSettings.run_advanscene_import != "")
123 	{
124 		std::string fname = CommonSettings.run_advanscene_import;
125 		std::string fname_out = fname + ".ddb";
126 		EMUFILE_FILE outf(fname_out,"wb");
127 		u32 ret = advsc.convertDB(fname.c_str(),&outf);
128 		if(ret == 0)
129 			exit(0);
130 		else exit(1);
131 	}
132 }
133 
NDS_Init()134 int NDS_Init()
135 {
136 	nds.idleFrameCounter = 0;
137 	memset(nds.runCycleCollector,0,sizeof(nds.runCycleCollector));
138 	MMU_Init();
139 
140 	//got to print this somewhere..
141 	printf("%s\n", EMU_DESMUME_NAME_AND_VERSION());
142 
143 	{
144 		char	buf[PATH_MAX_LENGTH];
145 		memset(buf, 0, sizeof(buf));
146 		strcpy(buf, path.pathToModule);
147 		strcat(buf, "desmume.ddb");							// DeSmuME database	:)
148 		advsc.setDatabase(buf);
149 
150 		//why is this done here? shitty engineering. not intended.
151 		NDS_RunAdvansceneAutoImport();
152 	}
153 
154 	armcpu_new(&NDS_ARM9,0);
155 	NDS_ARM9.SetBaseMemoryInterface(&arm9_base_memory_iface);
156 	NDS_ARM9.SetBaseMemoryInterfaceData(NULL);
157 	NDS_ARM9.ResetMemoryInterfaceToBase();
158 
159 	armcpu_new(&NDS_ARM7,1);
160 	NDS_ARM7.SetBaseMemoryInterface(&arm7_base_memory_iface);
161 	NDS_ARM7.SetBaseMemoryInterfaceData(NULL);
162 	NDS_ARM7.ResetMemoryInterfaceToBase();
163 
164    if (GPU != NULL)
165 		delete GPU;
166 
167 	GPU = new GPUSubsystem;
168 
169 	if (SPU_Init(SNDCORE_DUMMY, 740) != 0)
170 		return -1;
171 
172 	WIFI_Init() ;
173 
174 	cheats = new CHEATS();
175 
176 	return 0;
177 }
178 
NDS_DeInit(void)179 void NDS_DeInit(void)
180 {
181 	gameInfo.closeROM();
182 	SPU_DeInit();
183 
184    delete GPU;
185    GPU = NULL;
186 
187 	MMU_DeInit();
188 
189 	WIFI_DeInit();
190 
191 	delete cheats;
192 	cheats = NULL;
193 
194 #ifdef HAVE_JIT
195 	arm_jit_close();
196 #endif
197 
198 #ifdef LOG_ARM7
199 	if (fp_dis7 != NULL)
200 	{
201 		fclose(fp_dis7);
202 		fp_dis7 = NULL;
203 	}
204 #endif
205 
206 #ifdef LOG_ARM9
207 	if (fp_dis9 != NULL)
208 	{
209 		fclose(fp_dis9);
210 		fp_dis9 = NULL;
211 	}
212 #endif
213 }
214 
NDS_getROMHeader(void)215 NDS_header* NDS_getROMHeader(void)
216 {
217 	NDS_header *newHeader = new NDS_header;
218 	memcpy(newHeader, &gameInfo.header, sizeof(NDS_header));
219 
220 	return newHeader;
221 }
222 
223 #ifdef DEBUG
debug()224 void debug()
225 {
226 	//if(NDS_ARM9.R[15]==0x020520DC) emu_halt();
227 	//DSLinux
228 	//if(NDS_ARM9.CPSR.bits.mode == 0) emu_halt();
229 	//if((NDS_ARM9.R[15]&0xFFFFF000)==0) emu_halt();
230 	//if((NDS_ARM9.R[15]==0x0201B4F4)/*&&(NDS_ARM9.R[1]==0x0)*/) emu_halt();
231 	//AOE
232 	//if((NDS_ARM9.R[15]==0x01FFE194)&&(NDS_ARM9.R[0]==0)) emu_halt();
233 	//if((NDS_ARM9.R[15]==0x01FFE134)&&(NDS_ARM9.R[0]==0)) emu_halt();
234 
235 	//BBMAN
236 	//if(NDS_ARM9.R[15]==0x02098B4C) emu_halt();
237 	//if(NDS_ARM9.R[15]==0x02004924) emu_halt();
238 	//if(NDS_ARM9.R[15]==0x02004890) emu_halt();
239 
240 	//if(NDS_ARM9.R[15]==0x0202B800) emu_halt();
241 	//if(NDS_ARM9.R[15]==0x0202B3DC) emu_halt();
242 	//if((NDS_ARM9.R[1]==0x9AC29AC1)&&(!fait)) {emu_halt();fait = TRUE;}
243 	//if(NDS_ARM9.R[1]==0x0400004A) {emu_halt();fait = TRUE;}
244 	/*if(NDS_ARM9.R[4]==0x2E33373C) emu_halt();
245 	if(NDS_ARM9.R[15]==0x02036668) //emu_halt();
246 	{
247 	nds.logcount++;
248 	sprintf(logbuf, "%d %08X", nds.logcount, NDS_ARM9.R[13]);
249 	log::ajouter(logbuf);
250 	if(nds.logcount==89) execute=FALSE;
251 	}*/
252 	//if(NDS_ARM9.instruction==0) emu_halt();
253 	//if((NDS_ARM9.R[15]>>28)) emu_halt();
254 }
255 #endif
256 
257 
RomBanner(bool defaultInit)258 RomBanner::RomBanner(bool defaultInit)
259 {
260 	if(!defaultInit) return;
261 	version = 1; //Version  (0001h)
262 	crc16 = 0; //CRC16 across entries 020h..83Fh
263 	memset(reserved,0,sizeof(reserved));
264 	memset(bitmap,0,sizeof(bitmap));
265 	memset(palette,0,sizeof(palette));
266 	memset(titles,0,sizeof(titles));
267 	memset(end0xFF,0,sizeof(end0xFF));
268 }
269 
hasRomBanner()270 bool GameInfo::hasRomBanner()
271 {
272 	if(header.IconOff + sizeof(RomBanner) > romsize)
273 		return false;
274 	else return true;
275 }
276 
getRomBanner()277 const RomBanner& GameInfo::getRomBanner()
278 {
279 	return banner;
280 }
281 
populate()282 void GameInfo::populate()
283 {
284 	const char regions_index[] = "JPFSEODIRKHXVWUC";
285 	const char *regions[] = {
286 					"???",
287 					"JPN",		// J
288 					"EUR",		// P
289 					"FRA",		// F
290 					"ESP",		// S
291 					"USA",		// E
292 					"INT",		// O
293 					"NOE",		// D
294 					"ITA",		// I
295 					"RUS",		// R
296 					"KOR",		// K
297 					"HOL",		// H
298 					"EUU",		// X
299 					"EUU",		// V
300 					"EUU",		// W
301 					"AUS",		// U
302 					"CHN",		// C
303 
304 	};
305 
306 	memset(ROMserial, 0, sizeof(ROMserial));
307 	memset(ROMname, 0, sizeof(ROMname));
308 
309 	if(isHomebrew())
310 	{
311 		//we can't really make a serial for a homebrew game that hasnt set a game code
312 		strcpy(ROMserial, "Homebrew");
313 	}
314 	else
315 	{
316 		if (isDSiEnhanced())
317 			strcpy(ROMserial,"TWL-    -");
318 		else
319 			strcpy(ROMserial,"NTR-    -");
320 		memcpy(ROMserial+4, header.gameCode, 4);
321 
322 		u32 regions_num = ARRAY_SIZE(regions);
323 		u32 region = (u32)(std::max<s32>(strchr(regions_index,header.gameCode[3]) - regions_index + 1, 0));
324 
325 		if (region < regions_num)
326 			strcat(ROMserial, regions[region]);
327 		else
328 			strcat(ROMserial, "???");
329 	}
330 
331 	//rom name is probably set even in homebrew, so do it regardless
332 	memset(ROMname, 0, sizeof(ROMname));
333 	memcpy(ROMname, header.gameTile, 12);
334 	string_trim_whitespace(ROMname);
335 
336 		/*if(header.IconOff < romsize)
337 		{
338 			u8 num = (T1ReadByte((u8*)romdata, header.IconOff) == 1)?6:7;
339 			for (int i = 0; i < num; i++)
340 			{
341 				wcstombs(ROMfullName[i], (wchar_t *)(romdata+header.IconOff+0x240+(i*0x100)), 0x100);
342 				trim(ROMfullName[i]);
343 			}
344 		}*/
345 }
346 
loadROM(std::string fname,u32 type)347 bool GameInfo::loadROM(std::string fname, u32 type)
348 {
349 	//printf("ROM %s\n", CommonSettings.loadToMemory?"loaded to RAM":"stream from disk");
350 
351 	closeROM();
352 
353 	fROM = fopen(fname.c_str(), "rb");
354 	if (!fROM) return false;
355 
356 	headerOffset = (type == ROM_DSGBA)?DSGBA_LOADER_SIZE:0;
357 	fseek(fROM, 0, SEEK_END);
358 	romsize = ftell(fROM) - headerOffset;
359 	fseek(fROM, headerOffset, SEEK_SET);
360 
361 	bool res = (fread(&header, 1, sizeof(header), fROM) == sizeof(header));
362 
363 	if (res)
364 	{
365 #ifdef MSB_FIRST
366 		//endian swap necessary fields. It would be better if we made accessors for these. I wonder if you could make a macro for a field accessor that would take the bitsize and do the swap on the fly
367 		struct FieldSwap {
368 			const size_t offset;
369 			const size_t bytes;
370 		};
371 
372 		static const FieldSwap fieldSwaps[] = {
373 			{ offsetof(NDS_header,makerCode), 2},
374 
375 			{ offsetof(NDS_header,ARM9src), 4},
376 			{ offsetof(NDS_header,ARM9exe), 4},
377 			{ offsetof(NDS_header,ARM9cpy), 4},
378 			{ offsetof(NDS_header,ARM9binSize), 4},
379 			{ offsetof(NDS_header,ARM7src), 4},
380 			{ offsetof(NDS_header,ARM7exe), 4},
381 			{ offsetof(NDS_header,ARM7cpy), 4},
382 			{ offsetof(NDS_header,ARM7binSize), 4},
383 			{ offsetof(NDS_header,FNameTblOff), 4},
384 			{ offsetof(NDS_header,FNameTblSize), 4},
385 			{ offsetof(NDS_header,FATOff), 4},
386 			{ offsetof(NDS_header,FATSize), 4},
387 			{ offsetof(NDS_header,ARM9OverlayOff), 4},
388 			{ offsetof(NDS_header,ARM9OverlaySize), 4},
389 			{ offsetof(NDS_header,ARM7OverlayOff), 4},
390 			{ offsetof(NDS_header,ARM7OverlaySize), 4},
391 			{ offsetof(NDS_header,normalCmd), 4},
392 			{ offsetof(NDS_header,Key1Cmd), 4},
393 			{ offsetof(NDS_header,IconOff), 4},
394 
395 			{ offsetof(NDS_header,CRC16), 2},
396 			{ offsetof(NDS_header,ROMtimeout), 2},
397 
398 			{ offsetof(NDS_header,ARM9autoload), 4},
399 			{ offsetof(NDS_header,ARM7autoload), 4},
400 			{ offsetof(NDS_header,endROMoffset), 4},
401 			{ offsetof(NDS_header,HeaderSize), 4},
402 
403 			{ offsetof(NDS_header, ARM9module), 4},
404 			{ offsetof(NDS_header, ARM7module), 4},
405 
406 			{ offsetof(NDS_header,logoCRC16), 2},
407 			{ offsetof(NDS_header,headerCRC16), 2},
408 		};
409 
410 		for(size_t i = 0; i < ARRAY_SIZE(fieldSwaps); i++)
411 		{
412 			const u8 *fieldAddr = (u8 *)&header + fieldSwaps[i].offset;
413 
414 			switch(fieldSwaps[i].bytes)
415 			{
416 				case 2:
417 					*(u16 *)fieldAddr = LE_TO_LOCAL_16(*(u16 *)fieldAddr);
418 					break;
419 
420 				case 4:
421 					*(u32 *)fieldAddr = LE_TO_LOCAL_32(*(u32 *)fieldAddr);
422 					break;
423 			}
424 		}
425 #endif
426 		cardSize = (128 * 1024) << header.cardSize;
427 
428 		if (cardSize < romsize)
429 		{
430 			msgbox->warn("The ROM header is invalid.\nThe device size has been increased to allow for the provided file size.\n");
431 
432 			for (u32 i = header.cardSize; i < 0xF; i++)
433 			{
434 				if (((128 * 1024) << i) >= romsize)
435 				{
436 					header.cardSize = i;
437 					cardSize = (128 * 1024) << i;
438 					break;
439 				}
440 			}
441 		}
442 
443 		mask = (cardSize - 1);
444 		mask |= (mask >>1);
445 		mask |= (mask >>2);
446 		mask |= (mask >>4);
447 		mask |= (mask >>8);
448 		mask |= (mask >>16);
449 
450 		if (type == ROM_NDS)
451 		{
452 			size_t elements_read;
453 
454 			fseek(fROM, 0x4000 + headerOffset, SEEK_SET);
455 			elements_read = fread(&secureArea[0], 1, 0x4000, fROM);
456 			if (elements_read != 0x4000)
457 				printf("Unexpectedly short post-header bit.\n");
458 		}
459 
460 		if (CommonSettings.loadToMemory)
461 		{
462 			fseek(fROM, headerOffset, SEEK_SET);
463 
464 			romdata = new u8[romsize + 4];
465 			if (fread(romdata, 1, romsize, fROM) != romsize)
466 			{
467 				delete [] romdata; romdata = NULL;
468 				romsize = 0;
469 
470 				return false;
471 			}
472 
473 			if(hasRomBanner())
474 			{
475 				memcpy(&banner, romdata + header.IconOff, sizeof(RomBanner));
476 
477 				banner.version = LE_TO_LOCAL_16(banner.version);
478 				banner.crc16 = LE_TO_LOCAL_16(banner.crc16);
479 
480 				for(size_t i = 0; i < ARRAY_SIZE(banner.palette); i++)
481 				{
482 					banner.palette[i] = LE_TO_LOCAL_16(banner.palette[i]);
483 				}
484 			}
485 
486 			_isDSiEnhanced = (LE_TO_LOCAL_32(*(u32*)(romdata + 0x180) == 0x8D898581U) && LE_TO_LOCAL_32(*(u32*)(romdata + 0x184) == 0x8C888480U));
487 			fclose(fROM); fROM = NULL;
488 			return true;
489 		}
490 		_isDSiEnhanced = ((readROM(0x180) == 0x8D898581U) && (readROM(0x184) == 0x8C888480U));
491 		if (hasRomBanner())
492 		{
493 			size_t elements_read;
494 			const size_t elements_to_read = sizeof(RomBanner);
495 
496 			fseek(fROM, header.IconOff + headerOffset, SEEK_SET);
497 			elements_read = fread(&banner, 1, elements_to_read, fROM);
498 			if (elements_read != elements_to_read)
499 				printf("Unexpectedly short post-header bit.\n");
500 
501 			banner.version = LE_TO_LOCAL_16(banner.version);
502 			banner.crc16 = LE_TO_LOCAL_16(banner.crc16);
503 
504 			for(size_t i = 0; i < ARRAY_SIZE(banner.palette); i++)
505 			{
506 				banner.palette[i] = LE_TO_LOCAL_16(banner.palette[i]);
507 			}
508 		}
509 		fseek(fROM, headerOffset, SEEK_SET);
510 		lastReadPos = 0;
511 		return true;
512 	}
513 
514 	romsize = 0;
515 	fclose(fROM); fROM = NULL;
516 	return false;
517 }
518 
closeROM()519 void GameInfo::closeROM()
520 {
521 	if (fROM)
522 		fclose(fROM);
523 
524 	if (romdata)
525 		delete [] romdata;
526 
527 	fROM = NULL;
528 	romdata = NULL;
529 	romsize = 0;
530 	lastReadPos = 0xFFFFFFFF;
531 }
532 
readROM(u32 pos)533 u32 GameInfo::readROM(u32 pos)
534 {
535 	if (!romdata)
536 	{
537 		u32 data;
538 		if (lastReadPos != pos)
539 			fseek(fROM, pos + headerOffset, SEEK_SET);
540 		u32 num = fread(&data, 1, 4, fROM);
541 		lastReadPos = (pos + num);
542 		return LE_TO_LOCAL_32(data);
543 	}
544 	else
545 	{
546 		if(pos + 4 > romsize)
547 		{
548 			printf("Panic! GameInfo reading out of buffer!\n");
549 			exit(-1);
550 		}
551 		return LE_TO_LOCAL_32(*(u32*)(romdata + pos));
552 	}
553 }
554 
isDSiEnhanced()555 bool GameInfo::isDSiEnhanced()
556 {
557 	return _isDSiEnhanced;
558 }
559 
isHomebrew()560 bool GameInfo::isHomebrew()
561 {
562 	return ((header.ARM9src < 0x4000) && (T1ReadLong(header.logo, 0) != 0x51AEFF24) && (T1ReadLong(header.logo, 4) != 0x699AA221));
563 }
564 
rom_init_path(const char * filename,const char * physicalName,const char * logicalFilename)565 static int rom_init_path(const char *filename, const char *physicalName, const char *logicalFilename)
566 {
567 	u32	type = ROM_NDS;
568 
569 	path.init(logicalFilename? logicalFilename : filename);
570 
571 	if ( path.isdsgba(path.path)) {
572 		type = ROM_DSGBA;
573 		gameInfo.loadROM(path.path, type);
574 	}
575 	else if ( !strcasecmp(path.extension().c_str(), "nds")) {
576 		type = ROM_NDS;
577 		gameInfo.loadROM(physicalName ? physicalName : path.path, type); //n.b. this does nothing if the file can't be found (i.e. if it was an extracted tempfile)...
578 		//...but since the data was extracted to gameInfo then it is ok
579 	}
580 	//ds.gba in archives, it's already been loaded into memory at this point
581 	else if (logicalFilename && path.isdsgba(std::string(logicalFilename))) {
582 		type = ROM_DSGBA;
583 	} else {
584 		//well, try to load it as an nds rom anyway
585 		type = ROM_NDS;
586 		gameInfo.loadROM(physicalName ? physicalName : path.path, type);
587 	}
588 
589 	//check that size is at least the size of the header
590 	if (gameInfo.romsize < 352) {
591 		return -1;
592 	}
593 
594 	gameInfo.romType = type;
595 
596 	return 1;
597 }
598 
NDS_LoadROM(const char * filename,const char * physicalName,const char * logicalFilename)599 int NDS_LoadROM(const char *filename, const char *physicalName, const char *logicalFilename)
600 {
601 	int	ret;
602 	char	buf[PATH_MAX_LENGTH];
603 
604 	if (filename == NULL)
605 		return -1;
606 
607 	ret = rom_init_path(filename, physicalName, logicalFilename);
608 	if (ret < 1)
609 		return ret;
610 
611 	//check whether this rom is any kind of valid
612 	if(!CheckValidRom((u8*)&gameInfo.header, gameInfo.secureArea))
613 	{
614 		printf("Specified file is not a valid rom\n");
615 		return -1;
616 	}
617 
618 	gameInfo.populate();
619 
620 
621 	if (CommonSettings.loadToMemory)
622 		gameInfo.crc = crc32(0, (u8*)gameInfo.romdata, gameInfo.romsize);
623 	else
624 		gameInfo.crc = 0;
625 
626 	gameInfo.chipID  = 0xC2;														// The Manufacturer ID is defined by JEDEC (C2h = Macronix)
627 	if (!gameInfo.isHomebrew())
628 	{
629 		gameInfo.chipID |= ((((128 << gameInfo.header.cardSize) / 1024) - 1) << 8);		// Chip size in megabytes minus 1
630 																						// (07h = 8MB, 0Fh = 16MB, 1Fh = 32MB, 3Fh = 64MB, 7Fh = 128MB)
631 
632 		// flags
633 		// 0: Unknown
634 		// 1: Unknown
635 		// 2: Unknown
636 		// 3: Unknown
637 		// 4: Unknown
638 		// 5: DSi? (if set to 1 then DSi Enhanced games send command D6h to Slot1)
639 		// 6: Unknown
640 		// 7: ROM speed (Secure Area Block transfer mode (trasfer 8x200h or 1000h bytes)
641 		// TODO:
642 		//if (gameInfo.isDSiEnhanced())
643 		//		gameInfo.chipID |= (0x40 << 24);
644 		gameInfo.chipID |= (0x00 << 24);
645 	}
646 
647 #ifdef DEBUG
648 	INFO("\nROM game code: %c%c%c%c\n", gameInfo.header.gameCode[0], gameInfo.header.gameCode[1], gameInfo.header.gameCode[2], gameInfo.header.gameCode[3]);
649 	if (gameInfo.crc)
650 		INFO("ROM crc: %08X\n", gameInfo.crc);
651 	if (!gameInfo.isHomebrew())
652 	{
653 		INFO("ROM serial: %s\n", gameInfo.ROMserial);
654 		INFO("ROM chipID: %08X\n", gameInfo.chipID);
655 		INFO("ROM internal name: %s\n", gameInfo.ROMname);
656 		if (gameInfo.isDSiEnhanced()) INFO("ROM DSi Enhanced\n");
657 	}
658 	INFO("ROM developer: %s\n", ((gameInfo.header.makerCode == 0) && gameInfo.isHomebrew())
659          ? "Homebrew" :
660          getDeveloperNameByID(gameInfo.header.makerCode));
661 #endif
662 
663 	buf[0] = gameInfo.header.gameCode[0];
664 	buf[1] = gameInfo.header.gameCode[1];
665 	buf[2] = gameInfo.header.gameCode[2];
666 	buf[3] = gameInfo.header.gameCode[3];
667 	buf[4] = 0;
668 	if (advsc.checkDB(buf, gameInfo.crc))
669 	{
670 		u8 sv = advsc.getSaveType();
671 		printf("Found in game database by %s:\n", advsc.getIdMethod());
672 		printf("\t* ROM serial:\t\t%s\n", advsc.getSerial());
673 		printf("\t* ROM save type:\t");
674 		if (sv == 0xFF)
675 			printf("Unknown");
676 		else
677 			if (sv == 0xFE)
678 				printf("None");
679 			else
680 			{
681 				printf("%s", save_types[sv + 1].descr);
682 				if (CommonSettings.autodetectBackupMethod == 1)
683 					backup_setManualBackupType(sv + 1);
684 			}
685 		printf("\n\t* ROM crc:\t\t%08X\n", advsc.getCRC32());
686 	}
687 	printf("\n");
688 
689 	//for homebrew, try auto-patching DLDI. should be benign if there is no DLDI or if it fails
690 	if(gameInfo.isHomebrew())
691 	{
692 		if(!CommonSettings.loadToMemory)
693 			msgbox->warn("Sorry.. right now, you can't use the default (stream rom from disk) with homebrew due to a bug with DLDI-autopatching");
694 		if (slot1_GetCurrentType() == NDS_SLOT1_R4)
695 			DLDI_tryPatch((void*)gameInfo.romdata, gameInfo.romsize, 1);
696 		else
697 			if (slot2_GetCurrentType() == NDS_SLOT2_CFLASH)
698 				DLDI_tryPatch((void*)gameInfo.romdata, gameInfo.romsize, 0);
699 
700 	}
701 
702 	if (cheats != NULL)
703 	{
704 		memset(buf, 0, sizeof(buf));
705 		path.getpathnoext(path.CHEATS, buf);
706 		strcat(buf, ".dct");						// DeSmuME cheat		:)
707 		cheats->init(buf);
708 	}
709 
710 	NDS_Reset();
711 
712 	return ret;
713 }
714 
NDS_FreeROM(void)715 void NDS_FreeROM(void)
716 {
717 	gameInfo.closeROM();
718 }
719 
NDS_Sleep()720 void NDS_Sleep() { nds.sleeping = TRUE; }
721 
NDS_TriggerCardEjectIRQ()722 void NDS_TriggerCardEjectIRQ()
723 {
724 	NDS_makeIrq(ARMCPU_ARM7, IRQ_BIT_GC_IREQ_MC);
725 	NDS_makeIrq(ARMCPU_ARM9, IRQ_BIT_GC_IREQ_MC); //zero added on 11-aug-2013 with no proof of accuracy
726 }
727 
728 
729 class FrameSkipper
730 {
731 public:
RequestSkip()732 	void RequestSkip()
733 	{
734 		nextSkip = true;
735 	}
OmitSkip(bool force,bool forceEvenIfCapturing=false)736 	void OmitSkip(bool force, bool forceEvenIfCapturing=false)
737 	{
738 		nextSkip = false;
739 		if((force && consecutiveNonCaptures > 30) || forceEvenIfCapturing)
740 		{
741 			SkipCur2DFrame = false;
742 			SkipCur3DFrame = false;
743 			SkipNext2DFrame = false;
744 			if(forceEvenIfCapturing)
745 				consecutiveNonCaptures = 0;
746 		}
747 	}
Advance()748 	void Advance()
749 	{
750       const GPUEngineA *mainEngine = GPU->GetEngineMain();
751 		bool capturing = (mainEngine->dispCapCnt.enabled || (mainEngine->dispCapCnt.val & 0x80000000));
752 
753 
754 		if(capturing && consecutiveNonCaptures > 30)
755 		{
756 			// the worst-looking graphics corruption problems from frameskip
757 			// are the result of skipping the capture on first frame it turns on.
758 			// so we do this to handle the capture immediately,
759 			// despite the risk of 1 frame of 2d/3d mismatch or wrong screen display.
760 			SkipNext2DFrame = false;
761 			nextSkip = false;
762 		}
763       else if((lastDisplayTarget != mainEngine->GetDisplayByID()) && lastSkip && !skipped)
764 		{
765 			// if we're switching from not skipping to skipping
766 			// and the screens are also switching around this frame,
767 			// go for 1 extra frame without skipping.
768 			// this avoids the scenario where we only draw one of the two screens
769 			// when a game is switching screens every frame.
770 			nextSkip = false;
771 		}
772 
773 		if(capturing)
774 			consecutiveNonCaptures = 0;
775 		else if(!(consecutiveNonCaptures > 9000)) // arbitrary cap to avoid eventual wrap
776 			consecutiveNonCaptures++;
777 
778       lastDisplayTarget = mainEngine->GetDisplayByID();
779 		lastSkip = skipped;
780 		skipped = nextSkip;
781 		nextSkip = false;
782 
783 		SkipCur2DFrame = SkipNext2DFrame;
784 		SkipCur3DFrame = skipped;
785 		SkipNext2DFrame = skipped;
786 	}
ShouldSkip2D()787 	FORCEINLINE bool ShouldSkip2D()
788 	{
789 		return SkipCur2DFrame;
790 	}
ShouldSkip3D()791 	FORCEINLINE bool ShouldSkip3D()
792 	{
793 		return SkipCur3DFrame;
794 	}
FrameSkipper()795 	FrameSkipper()
796 	{
797 		nextSkip = false;
798 		skipped = false;
799 		lastSkip = false;
800       lastDisplayTarget = NDSDisplayID_Main;
801 		SkipCur2DFrame = false;
802 		SkipCur3DFrame = false;
803 		SkipNext2DFrame = false;
804 		consecutiveNonCaptures = 0;
805 	}
806 private:
807 	bool nextSkip;
808 	bool skipped;
809 	bool lastSkip;
810    NDSDisplayID lastDisplayTarget;
811 	int consecutiveNonCaptures;
812 	bool SkipCur2DFrame;
813 	bool SkipCur3DFrame;
814 	bool SkipNext2DFrame;
815 };
816 static FrameSkipper frameSkipper;
817 
818 
NDS_SkipNextFrame()819 void NDS_SkipNextFrame() {
820    frameSkipper.RequestSkip();
821 }
NDS_OmitFrameSkip(int force)822 void NDS_OmitFrameSkip(int force) {
823 	frameSkipper.OmitSkip(force > 0, force > 1);
824 }
825 
826 #define INDEX(i) ((((i)>>16)&0xFF0)|(((i)>>4)&0xF))
827 
828 
829 enum ESI_DISPCNT
830 {
831 	ESI_DISPCNT_HStart, ESI_DISPCNT_HStartIRQ, ESI_DISPCNT_HDraw, ESI_DISPCNT_HBlank
832 };
833 
834 u64 nds_timer;
835 u64 nds_arm9_timer, nds_arm7_timer;
836 
837 static const u64 kNever = 0xFFFFFFFFFFFFFFFFULL;
838 
839 struct TSequenceItem
840 {
841 	u64 timestamp;
842 	u32 param;
843 	bool enabled;
844 
saveTSequenceItem845 	virtual void save(EMUFILE* os)
846 	{
847 		write64le(timestamp,os);
848 		write32le(param,os);
849 		writebool(enabled,os);
850 	}
851 
loadTSequenceItem852 	virtual bool load(EMUFILE* is)
853 	{
854 		if(read64le(&timestamp,is) != 1) return false;
855 		if(read32le(&param,is) != 1) return false;
856 		if(readbool(&enabled,is) != 1) return false;
857 		return true;
858 	}
859 
isTriggeredTSequenceItem860 	FORCEINLINE bool isTriggered()
861 	{
862 		return enabled && nds_timer >= timestamp;
863 	}
864 
nextTSequenceItem865 	FORCEINLINE u64 next()
866 	{
867 		return timestamp;
868 	}
869 };
870 
871 struct TSequenceItem_GXFIFO : public TSequenceItem
872 {
isTriggeredTSequenceItem_GXFIFO873 	FORCEINLINE bool isTriggered()
874 	{
875 		return enabled && nds_timer >= MMU.gfx3dCycles;
876 	}
877 
execTSequenceItem_GXFIFO878 	FORCEINLINE void exec()
879 	{
880 #ifndef NDEBUG
881 		IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[4]++);
882 #endif
883 		while(isTriggered()) {
884 			enabled = false;
885 			gfx3d_execute3D();
886 		}
887 	}
888 
nextTSequenceItem_GXFIFO889 	FORCEINLINE u64 next()
890 	{
891 		if(enabled) return MMU.gfx3dCycles;
892 		else return kNever;
893 	}
894 };
895 
896 template<int procnum, int num> struct TSequenceItem_Timer : public TSequenceItem
897 {
isTriggeredTSequenceItem_Timer898 	FORCEINLINE bool isTriggered()
899 	{
900 		return enabled && nds_timer >= nds.timerCycle[procnum][num];
901 	}
902 
scheduleTSequenceItem_Timer903 	FORCEINLINE void schedule()
904 	{
905 		enabled = MMU.timerON[procnum][num] && MMU.timerMODE[procnum][num] != 0xFFFF;
906 	}
907 
nextTSequenceItem_Timer908 	FORCEINLINE u64 next()
909 	{
910 		return nds.timerCycle[procnum][num];
911 	}
912 
execTSequenceItem_Timer913 	FORCEINLINE void exec()
914 	{
915 #ifndef NDEBUG
916 		IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[13+procnum*4+num]++);
917 #endif
918 		u8* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG;
919 		bool first = true;
920 		//we'll need to check chained timers..
921 		for(int i=num;i<4;i++)
922 		{
923 			bool over = false;
924 			//maybe too many checks if this is here, but we need it here for now
925 			if(!MMU.timerON[procnum][i]) return;
926 
927 			if(MMU.timerMODE[procnum][i] == 0xFFFF)
928 			{
929 				++(MMU.timer[procnum][i]);
930 				over = !MMU.timer[procnum][i];
931 			}
932 			else
933 			{
934 				if(!first) break; //this timer isn't chained. break the chain
935 				first = false;
936 
937 				over = true;
938 				int remain = 65536 - MMU.timerReload[procnum][i];
939 				int ctr=0;
940 				while(nds.timerCycle[procnum][i] <= nds_timer) {
941 					nds.timerCycle[procnum][i] += (remain << MMU.timerMODE[procnum][i]);
942 					ctr++;
943 				}
944 #ifndef NDEBUG
945 				if(ctr>1) {
946 					printf("yikes!!!!! please report!\n");
947 				}
948 #endif
949 			}
950 
951 			if(over)
952 			{
953 				MMU.timer[procnum][i] = MMU.timerReload[procnum][i];
954 				if(T1ReadWord(regs, 0x102 + i*4) & 0x40)
955 				{
956 					NDS_makeIrq(procnum, IRQ_BIT_TIMER_0 + i);
957 				}
958 			}
959 			else
960 				break; //no more chained timers to trigger. we're done here
961 		}
962 	}
963 };
964 
965 template<int procnum, int chan> struct TSequenceItem_DMA : public TSequenceItem
966 {
967 	DmaController* controller;
968 
isTriggeredTSequenceItem_DMA969 	FORCEINLINE bool isTriggered()
970 	{
971 		return (controller->dmaCheck && nds_timer>= controller->nextEvent);
972 	}
973 
isEnabledTSequenceItem_DMA974 	FORCEINLINE bool isEnabled() {
975 		return controller->dmaCheck?TRUE:FALSE;
976 	}
977 
nextTSequenceItem_DMA978 	FORCEINLINE u64 next()
979 	{
980 		return controller->nextEvent;
981 	}
982 
execTSequenceItem_DMA983 	FORCEINLINE void exec()
984 	{
985 #ifndef NDEBUG
986 		IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[5+procnum*4+chan]++);
987 #endif
988 
989 		//if (nds.freezeBus) return;
990 
991 		//printf("exec from TSequenceItem_DMA: %d %d\n",procnum,chan);
992 		controller->exec();
993 //		//give gxfifo dmas a chance to re-trigger
994 //		if(MMU.DMAStartTime[procnum][chan] == EDMAMode_GXFifo) {
995 //			MMU.DMAing[procnum][chan] = FALSE;
996 //			if (gxFIFO.size <= 127)
997 //			{
998 //				execHardware_doDma(procnum,chan,EDMAMode_GXFifo);
999 //				if (MMU.DMACompleted[procnum][chan])
1000 //					goto docomplete;
1001 //				else return;
1002 //			}
1003 //		}
1004 //
1005 //docomplete:
1006 //		if (MMU.DMACompleted[procnum][chan])
1007 //		{
1008 //			u8* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG;
1009 //
1010 //			//disable the channel
1011 //			if(MMU.DMAStartTime[procnum][chan] != EDMAMode_GXFifo) {
1012 //				T1WriteLong(regs, 0xB8 + (0xC*chan), T1ReadLong(regs, 0xB8 + (0xC*chan)) & 0x7FFFFFFF);
1013 //				MMU.DMACrt[procnum][chan] &= 0x7FFFFFFF; //blehhh i hate this shit being mirrored in memory
1014 //			}
1015 //
1016 //			if((MMU.DMACrt[procnum][chan])&(1<<30)) {
1017 //				if(procnum==0) NDS_makeARM9Int(8+chan);
1018 //				else NDS_makeARM7Int(8+chan);
1019 //			}
1020 //
1021 //			MMU.DMAing[procnum][chan] = FALSE;
1022 //		}
1023 
1024 	}
1025 };
1026 
1027 struct TSequenceItem_divider : public TSequenceItem
1028 {
isTriggeredTSequenceItem_divider1029 	FORCEINLINE bool isTriggered()
1030 	{
1031 		return MMU.divRunning && nds_timer >= MMU.divCycles;
1032 	}
1033 
isEnabledTSequenceItem_divider1034 	bool isEnabled() { return MMU.divRunning!=0; }
1035 
nextTSequenceItem_divider1036 	FORCEINLINE u64 next()
1037 	{
1038 		return MMU.divCycles;
1039 	}
1040 
execTSequenceItem_divider1041 	void exec()
1042 	{
1043 #ifndef NDEBUG
1044 		IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[2]++);
1045 #endif
1046 		MMU_new.div.busy = 0;
1047 #ifdef HOST_64
1048 		T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, MMU.divResult);
1049 		T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, MMU.divMod);
1050 #else
1051 		T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, (u32)MMU.divResult);
1052 		T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, (u32)(MMU.divResult >> 32));
1053 		T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, (u32)MMU.divMod);
1054 		T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, (u32)(MMU.divMod >> 32));
1055 #endif
1056 		MMU.divRunning = FALSE;
1057 	}
1058 
1059 };
1060 
1061 struct TSequenceItem_sqrtunit : public TSequenceItem
1062 {
isTriggeredTSequenceItem_sqrtunit1063 	FORCEINLINE bool isTriggered()
1064 	{
1065 		return MMU.sqrtRunning && nds_timer >= MMU.sqrtCycles;
1066 	}
1067 
isEnabledTSequenceItem_sqrtunit1068 	bool isEnabled() { return MMU.sqrtRunning!=0; }
1069 
nextTSequenceItem_sqrtunit1070 	FORCEINLINE u64 next()
1071 	{
1072 		return MMU.sqrtCycles;
1073 	}
1074 
execTSequenceItem_sqrtunit1075 	FORCEINLINE void exec()
1076 	{
1077 #ifndef NDEBUG
1078 		IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[3]++);
1079 #endif
1080 		MMU_new.sqrt.busy = 0;
1081 		T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, MMU.sqrtResult);
1082 		MMU.sqrtRunning = FALSE;
1083 	}
1084 
1085 };
1086 
1087 struct Sequencer
1088 {
1089 	bool nds_vblankEnded;
1090 	bool reschedule;
1091 	TSequenceItem dispcnt;
1092 	TSequenceItem wifi;
1093 	TSequenceItem_divider divider;
1094 	TSequenceItem_sqrtunit sqrtunit;
1095 	TSequenceItem_GXFIFO gxfifo;
1096 	TSequenceItem_DMA<0,0> dma_0_0; TSequenceItem_DMA<0,1> dma_0_1;
1097 	TSequenceItem_DMA<0,2> dma_0_2; TSequenceItem_DMA<0,3> dma_0_3;
1098 	TSequenceItem_DMA<1,0> dma_1_0; TSequenceItem_DMA<1,1> dma_1_1;
1099 	TSequenceItem_DMA<1,2> dma_1_2; TSequenceItem_DMA<1,3> dma_1_3;
1100 	TSequenceItem_Timer<0,0> timer_0_0; TSequenceItem_Timer<0,1> timer_0_1;
1101 	TSequenceItem_Timer<0,2> timer_0_2; TSequenceItem_Timer<0,3> timer_0_3;
1102 	TSequenceItem_Timer<1,0> timer_1_0; TSequenceItem_Timer<1,1> timer_1_1;
1103 	TSequenceItem_Timer<1,2> timer_1_2; TSequenceItem_Timer<1,3> timer_1_3;
1104 
1105 	void init();
1106 
1107 	void execHardware();
1108 	u64 findNext();
1109 
saveSequencer1110 	void save(EMUFILE* os)
1111 	{
1112 		write64le(nds_timer,os);
1113 		write64le(nds_arm9_timer,os);
1114 		write64le(nds_arm7_timer,os);
1115 		dispcnt.save(os);
1116 		divider.save(os);
1117 		sqrtunit.save(os);
1118 		gxfifo.save(os);
1119 		wifi.save(os);
1120 #define SAVE(I,X,Y) I##_##X##_##Y .save(os);
1121 		SAVE(timer,0,0); SAVE(timer,0,1); SAVE(timer,0,2); SAVE(timer,0,3);
1122 		SAVE(timer,1,0); SAVE(timer,1,1); SAVE(timer,1,2); SAVE(timer,1,3);
1123 		SAVE(dma,0,0); SAVE(dma,0,1); SAVE(dma,0,2); SAVE(dma,0,3);
1124 		SAVE(dma,1,0); SAVE(dma,1,1); SAVE(dma,1,2); SAVE(dma,1,3);
1125 #undef SAVE
1126 	}
1127 
loadSequencer1128 	bool load(EMUFILE* is, int version)
1129 	{
1130 		if(read64le(&nds_timer,is) != 1) return false;
1131 		if(read64le(&nds_arm9_timer,is) != 1) return false;
1132 		if(read64le(&nds_arm7_timer,is) != 1) return false;
1133 		if(!dispcnt.load(is)) return false;
1134 		if(!divider.load(is)) return false;
1135 		if(!sqrtunit.load(is)) return false;
1136 		if(!gxfifo.load(is)) return false;
1137 		if(version >= 1) if(!wifi.load(is)) return false;
1138 #define LOAD(I,X,Y) if(!I##_##X##_##Y .load(is)) return false;
1139 		LOAD(timer,0,0); LOAD(timer,0,1); LOAD(timer,0,2); LOAD(timer,0,3);
1140 		LOAD(timer,1,0); LOAD(timer,1,1); LOAD(timer,1,2); LOAD(timer,1,3);
1141 		LOAD(dma,0,0); LOAD(dma,0,1); LOAD(dma,0,2); LOAD(dma,0,3);
1142 		LOAD(dma,1,0); LOAD(dma,1,1); LOAD(dma,1,2); LOAD(dma,1,3);
1143 #undef LOAD
1144 
1145 		return true;
1146 	}
1147 
1148 } sequencer;
1149 
NDS_RescheduleGXFIFO(u32 cost)1150 void NDS_RescheduleGXFIFO(u32 cost)
1151 {
1152 	if(!sequencer.gxfifo.enabled) {
1153 		MMU.gfx3dCycles = nds_timer;
1154 		sequencer.gxfifo.enabled = true;
1155 	}
1156 	MMU.gfx3dCycles += cost;
1157 	NDS_Reschedule();
1158 }
1159 
NDS_RescheduleTimers()1160 void NDS_RescheduleTimers()
1161 {
1162 #define check(X,Y) sequencer.timer_##X##_##Y .schedule();
1163 	check(0,0); check(0,1); check(0,2); check(0,3);
1164 	check(1,0); check(1,1); check(1,2); check(1,3);
1165 #undef check
1166 
1167 	NDS_Reschedule();
1168 }
1169 
NDS_RescheduleDMA()1170 void NDS_RescheduleDMA()
1171 {
1172 	//TBD
1173 	NDS_Reschedule();
1174 
1175 }
1176 
initSchedule()1177 static void initSchedule()
1178 {
1179 	sequencer.init();
1180 
1181 	//begin at the very end of the last scanline
1182 	//so that at t=0 we can increment to scanline=0
1183 	nds.VCount = 262;
1184 
1185 	sequencer.nds_vblankEnded = false;
1186 }
1187 
1188 
1189 // 2196372 ~= (ARM7_CLOCK << 16) / 1000000
1190 // This value makes more sense to me, because:
1191 // ARM7_CLOCK   = 33.51 mhz
1192 //				= 33513982 cycles per second
1193 // 				= 33.513982 cycles per microsecond
1194 const u64 kWifiCycles = 67;//34*2;
1195 //(this isn't very precise. I don't think it needs to be)
1196 
init()1197 void Sequencer::init()
1198 {
1199 	NDS_RescheduleTimers();
1200 	NDS_RescheduleDMA();
1201 
1202 	reschedule = false;
1203 	nds_timer = 0;
1204 	nds_arm9_timer = 0;
1205 	nds_arm7_timer = 0;
1206 
1207 	dispcnt.enabled = true;
1208 	dispcnt.param = ESI_DISPCNT_HStart;
1209 	dispcnt.timestamp = 0;
1210 
1211 	gxfifo.enabled = false;
1212 
1213 	dma_0_0.controller = &MMU_new.dma[0][0];
1214 	dma_0_1.controller = &MMU_new.dma[0][1];
1215 	dma_0_2.controller = &MMU_new.dma[0][2];
1216 	dma_0_3.controller = &MMU_new.dma[0][3];
1217 	dma_1_0.controller = &MMU_new.dma[1][0];
1218 	dma_1_1.controller = &MMU_new.dma[1][1];
1219 	dma_1_2.controller = &MMU_new.dma[1][2];
1220 	dma_1_3.controller = &MMU_new.dma[1][3];
1221 
1222 
1223 	#ifdef EXPERIMENTAL_WIFI_COMM
1224 	wifi.enabled = true;
1225 	wifi.timestamp = kWifiCycles;
1226 	#else
1227 	wifi.enabled = false;
1228 	#endif
1229 }
1230 
execHardware_hblank()1231 static void execHardware_hblank()
1232 {
1233 	//this logic keeps moving around.
1234 	//now, we try and give the game as much time as possible to finish doing its work for the scanline,
1235 	//by drawing scanline N at the end of drawing time (but before subsequent interrupt or hdma-driven events happen)
1236 	//don't try to do this at the end of the scanline, because some games (sonic classics) may use hblank IRQ to set
1237 	//scroll regs for the next scanline
1238 	if(nds.VCount<192)
1239 	{
1240       GPU->RenderLine(nds.VCount, frameSkipper.ShouldSkip2D());
1241 
1242 		//trigger hblank dmas
1243 		//but notice, we do that just after we finished drawing the line
1244 		//(values copied by this hdma should not be used until the next scanline)
1245 		triggerDma(EDMAMode_HBlank);
1246 	}
1247 
1248 #if 0
1249 	if(nds.VCount==262)
1250 	{
1251 		//we need to trigger one last hblank dma since
1252 		//a. we're sort of lagged behind by one scanline
1253 		//b. i think that 193 hblanks actually fire (one for the hblank in scanline 262)
1254 		//this is demonstrated by NSMB splot-parallaxing clouds
1255 		//for some reason the game will setup two hdma scroll register buffers
1256 		//to be run consecutively, and unless we do this, the second buffer will be offset by one scanline
1257 		//causing a glitch in the 0th scanline
1258 		//triggerDma(EDMAMode_HBlank);
1259 
1260 		//BUT! this was removed in order to make glitches in megaman zero collection (mmz 4 1st level) work.
1261 		//and, it seems that it is no longer necessary in nsmb. perhaps something else fixed it
1262 	}
1263 #endif
1264 
1265 
1266 	//turn on hblank status bit
1267 	T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 2);
1268 	T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 2);
1269 
1270 	//fire hblank interrupts if necessary
1271 	if(T1ReadWord(MMU.ARM9_REG, 4) & 0x10) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_HBLANK);
1272 	if(T1ReadWord(MMU.ARM7_REG, 4) & 0x10) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_HBLANK);
1273 
1274 	//emulation housekeeping. for some reason we always do this at hblank,
1275 	//even though it sounds more reasonable to do it at hstart
1276 	SPU_Emulate_core();
1277 }
1278 
execHardware_hstart_vblankEnd()1279 static void execHardware_hstart_vblankEnd()
1280 {
1281 	sequencer.nds_vblankEnded = true;
1282 	sequencer.reschedule = true;
1283 
1284 	//turn off vblank status bit
1285 	T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & ~1);
1286 	T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & ~1);
1287 
1288 	//some emulation housekeeping
1289 	frameSkipper.Advance();
1290 
1291    if (GPU->GetWillAutoBlitNativeToCustomBuffer())
1292 	{
1293 		GPU->GetEngineMain()->BlitNativeToCustomFramebuffer();
1294 		GPU->GetEngineSub()->BlitNativeToCustomFramebuffer();
1295 	}
1296 }
1297 
execHardware_hstart_vblankStart()1298 static void execHardware_hstart_vblankStart()
1299 {
1300 	//printf("--------VBLANK!!!--------\n");
1301 
1302 	//fire vblank interrupts if necessary
1303 	for(int i=0;i<2;i++)
1304 		if(MMU.reg_IF_pending[i] & (1<<IRQ_BIT_LCD_VBLANK))
1305 		{
1306 			MMU.reg_IF_pending[i] &= ~(1<<IRQ_BIT_LCD_VBLANK);
1307 			NDS_makeIrq(i,IRQ_BIT_LCD_VBLANK);
1308 		}
1309 
1310 	//trigger vblank dmas
1311 	triggerDma(EDMAMode_VBlank);
1312 
1313 	//tracking for arm9 load average
1314 	nds.runCycleCollector[0][nds.idleFrameCounter] = 1120380-nds.idleCycles[0];
1315 	nds.runCycleCollector[1][nds.idleFrameCounter] = 1120380-nds.idleCycles[1];
1316 	nds.idleFrameCounter++;
1317 	nds.idleFrameCounter &= 15;
1318 	nds.idleCycles[0] = 0;
1319 	nds.idleCycles[1] = 0;
1320 }
1321 
execHardware_gen_vmatch_goal()1322 static u16 execHardware_gen_vmatch_goal()
1323 {
1324 	u16 vmatch = T1ReadWord(MMU.ARM9_REG, 4);
1325 	vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8)));
1326 	return vmatch;
1327 }
1328 
execHardware_hstart_vcount_irq()1329 static void execHardware_hstart_vcount_irq()
1330 {
1331 	//trigger pending VMATCH irqs
1332 	if(MMU.reg_IF_pending[ARMCPU_ARM9] & (1<<IRQ_BIT_LCD_VMATCH))
1333 	{
1334 		MMU.reg_IF_pending[ARMCPU_ARM9] &= ~(1<<IRQ_BIT_LCD_VMATCH);
1335 		NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_VMATCH);
1336 	}
1337 	if(MMU.reg_IF_pending[ARMCPU_ARM7] & (1<<IRQ_BIT_LCD_VMATCH))
1338 	{
1339 		MMU.reg_IF_pending[ARMCPU_ARM7] &= ~(1<<IRQ_BIT_LCD_VMATCH);
1340 		NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_VMATCH);
1341 	}
1342 }
1343 
execHardware_hstart_vcount()1344 static void execHardware_hstart_vcount()
1345 {
1346 	u16 vmatch = execHardware_gen_vmatch_goal();
1347 	if(nds.VCount==vmatch)
1348 	{
1349 		//arm9 vmatch
1350 		T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 4);
1351 		if(T1ReadWord(MMU.ARM9_REG, 4) & 32) {
1352 			MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VMATCH);
1353 		}
1354 	}
1355 	else
1356 		T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFB);
1357 
1358 	vmatch = T1ReadWord(MMU.ARM7_REG, 4);
1359 	vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8)));
1360 	if(nds.VCount==vmatch)
1361 	{
1362 		//arm7 vmatch
1363 		T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 4);
1364 		if(T1ReadWord(MMU.ARM7_REG, 4) & 32)
1365 			MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VMATCH);
1366 	}
1367 	else
1368 		T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFB);
1369 }
1370 
execHardware_hdraw()1371 static void execHardware_hdraw()
1372 {
1373 	//due to hacks in our selection of rendering time, we do not actually render here as intended.
1374 	//consider changing this if there is some problem with raster fx timing but check the documentation near the gpu rendering calls
1375 	//to make sure you check for regressions (nsmb, sonic classics, et al)
1376 }
1377 
execHardware_hstart_irq()1378 static void execHardware_hstart_irq()
1379 {
1380 	//this function very soon after the registers get updated to trigger IRQs
1381 	//this is necessary to fix "egokoro kyoushitsu" which idles waiting for vcount=192, which never happens due to a long vblank irq
1382 	//100% accurate emulation would require the read of VCOUNT to be in the pipeline already with the irq coming in behind it, thus
1383 	//allowing the vcount to register as 192 occasionally (maybe about 1 out of 28 frames)
1384 	//the actual length of the delay is in execHardware() where the events are scheduled
1385 	sequencer.reschedule = true;
1386 
1387    //when the vcount hits 192, vblank begins
1388 	if(nds.VCount==192)
1389 		execHardware_hstart_vblankStart();
1390 
1391 	execHardware_hstart_vcount_irq();
1392 }
1393 
execHardware_hstart()1394 static void execHardware_hstart()
1395 {
1396 	nds.VCount++;
1397 
1398    switch (nds.VCount)
1399    {
1400       case 214:
1401          if (CommonSettings.rigorous_timing)
1402             gfx3d_VBlankEndSignal(frameSkipper.ShouldSkip3D());
1403          break;
1404       case 263:
1405          //when the vcount hits 263 it rolls over to 0
1406          nds.VCount=0;
1407          break;
1408       case 262:
1409          //this should be 214, but we are going to be generous for games with tight timing
1410          //they shouldnt be changing any textures at 262 but they might accidentally still be at 214
1411          //so..
1412          if (!CommonSettings.rigorous_timing)
1413             gfx3d_VBlankEndSignal(frameSkipper.ShouldSkip3D());
1414 
1415          //when the vcount hits 262, vblank ends (oam pre-renders by one scanline)
1416          execHardware_hstart_vblankEnd();
1417          break;
1418       case 192:
1419          //turn on vblank status bit
1420          T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 1);
1421          T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1);
1422 
1423          //check whether we'll need to fire vblank irqs
1424          if(T1ReadWord(MMU.ARM9_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VBLANK);
1425          if(T1ReadWord(MMU.ARM7_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VBLANK);
1426 
1427          //this is important for the character select in Dragon Ball Kai - Ultimate Butouden
1428          //it seems if you allow the 3d to begin before the vblank, then it will get interrupted and not complete.
1429          //the game needs to pick up the gxstat reg busy as clear after it finishes processing vblank.
1430          //therefore, this can't happen until sometime after vblank.
1431          //devil survivor 2 will have screens get stuck if this is on any other scanline.
1432          //obviously 192 is the right choice.
1433          gfx3d_VBlankSignal();
1434          //this isnt important for any known game, but it would be nice to prove it.
1435          NDS_RescheduleGXFIFO(392*2);
1436          break;
1437    }
1438 
1439 	//write the new vcount
1440 	T1WriteWord(MMU.ARM9_REG, 6, nds.VCount);
1441 	T1WriteWord(MMU.ARM9_REG, 0x1006, nds.VCount);
1442 	T1WriteWord(MMU.ARM7_REG, 6, nds.VCount);
1443 	T1WriteWord(MMU.ARM7_REG, 0x1006, nds.VCount);
1444 
1445 	//turn off hblank status bit
1446 	T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFD);
1447 	T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFD);
1448 
1449 	//handle vcount status
1450 	execHardware_hstart_vcount();
1451 
1452 	//trigger hstart dmas
1453 	triggerDma(EDMAMode_HStart);
1454 
1455 	if(nds.VCount<192)
1456 	{
1457 		//this is hacky.
1458 		//there is a corresponding hack in doDMA.
1459 		//it should be driven by a fifo (and generate just in time as the scanline is displayed)
1460 		//but that isnt even possible until we have some sort of sub-scanline timing.
1461 		//it may not be necessary.
1462 		triggerDma(EDMAMode_MemDisplay);
1463 	}
1464 }
1465 
NDS_Reschedule()1466 void NDS_Reschedule()
1467 {
1468 #ifndef NDEBUG
1469 	IF_DEVELOPER(if(!sequencer.reschedule) DEBUG_statistics.sequencerExecutionCounters[0]++;);
1470 #endif
1471 	sequencer.reschedule = true;
1472 }
1473 
_fast_min32(u32 a,u32 b,u32 c,u32 d)1474 FORCEINLINE u32 _fast_min32(u32 a, u32 b, u32 c, u32 d)
1475 {
1476 	return ((( ((s32)(a-b)) >> (32-1)) & (c^d)) ^ d);
1477 }
1478 
_fast_min(u64 a,u64 b)1479 FORCEINLINE u64 _fast_min(u64 a, u64 b)
1480 {
1481 	//you might find that this is faster on a 64bit system; someone should try it
1482 	//http://aggregate.org/MAGIC/#Integer%20Selection
1483 	//u64 ret = (((((s64)(a-b)) >> (64-1)) & (a^b)) ^ b);
1484 	//assert(ret==min(a,b));
1485 	//return ret;
1486 
1487 	//but this ends up being the fastest on 32bits
1488 	return a<b?a:b;
1489 
1490 	//just for the record, I tried to do the 64bit math on a 32bit proc
1491 	//using sse2 and it was really slow
1492 	//__m128i __a; __a.m128i_u64[0] = a;
1493 	//__m128i __b; __b.m128i_u64[0] = b;
1494 	//__m128i xorval = _mm_xor_si128(__a,__b);
1495 	//__m128i temp = _mm_sub_epi64(__a,__b);
1496 	//temp.m128i_i64[0] >>= 63; //no 64bit shra in sse2, what a disappointment
1497 	//temp = _mm_and_si128(temp,xorval);
1498 	//temp = _mm_xor_si128(temp,__b);
1499 	//return temp.m128i_u64[0];
1500 }
1501 
1502 
1503 
findNext()1504 u64 Sequencer::findNext()
1505 {
1506 	//this one is always enabled so dont bother to check it
1507 	u64 next = dispcnt.next();
1508 
1509 	if(divider.isEnabled()) next = _fast_min(next,divider.next());
1510 	if(sqrtunit.isEnabled()) next = _fast_min(next,sqrtunit.next());
1511 	if(gxfifo.enabled) next = _fast_min(next,gxfifo.next());
1512 
1513 #ifdef EXPERIMENTAL_WIFI_COMM
1514 	next = _fast_min(next,wifi.next());
1515 #endif
1516 
1517 #define test(X,Y) if(dma_##X##_##Y .isEnabled()) next = _fast_min(next,dma_##X##_##Y .next());
1518 	test(0,0); test(0,1); test(0,2); test(0,3);
1519 	test(1,0); test(1,1); test(1,2); test(1,3);
1520 #undef test
1521 #define test(X,Y) if(timer_##X##_##Y .enabled) next = _fast_min(next,timer_##X##_##Y .next());
1522 	test(0,0); test(0,1); test(0,2); test(0,3);
1523 	test(1,0); test(1,1); test(1,2); test(1,3);
1524 #undef test
1525 
1526 	return next;
1527 }
1528 
execHardware()1529 void Sequencer::execHardware()
1530 {
1531 	if(dispcnt.isTriggered())
1532 	{
1533 #ifndef NDEBUG
1534 		IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[1]++);
1535 #endif
1536 
1537 		switch(dispcnt.param)
1538 		{
1539 		case ESI_DISPCNT_HStart:
1540 			execHardware_hstart();
1541 			//(used to be 3168)
1542 			//hstart is actually 8 dots before the visible drawing begins
1543 			//we're going to run 1 here and then run 7 in the next case
1544 			dispcnt.timestamp += 1*6*2;
1545 			dispcnt.param = ESI_DISPCNT_HStartIRQ;
1546 			break;
1547 		case ESI_DISPCNT_HStartIRQ:
1548 			execHardware_hstart_irq();
1549 			dispcnt.timestamp += 7*6*2;
1550 			dispcnt.param = ESI_DISPCNT_HDraw;
1551 			break;
1552 
1553 		case ESI_DISPCNT_HDraw:
1554 			//execHardware_hdraw();
1555 			//duration of non-blanking period is ~1606 clocks (gbatek agrees) [but says its different on arm7]
1556 			//im gonna call this 267 dots = 267*6=1602
1557 			//so, this event lasts 267 dots minus the 8 dot preroll
1558 			dispcnt.timestamp += (267-8)*6*2;
1559 			dispcnt.param = ESI_DISPCNT_HBlank;
1560 			break;
1561 
1562 		case ESI_DISPCNT_HBlank:
1563 			execHardware_hblank();
1564 			//(once this was 1092 or 1092/12=91 dots.)
1565 			//there are surely 355 dots per scanline, less 267 for non-blanking period. the rest is hblank and then after that is hstart
1566 			dispcnt.timestamp += (355-267)*6*2;
1567 			dispcnt.param = ESI_DISPCNT_HStart;
1568 			break;
1569 		}
1570 	}
1571 
1572 #ifdef EXPERIMENTAL_WIFI_COMM
1573 	if(wifi.isTriggered())
1574 	{
1575 		WIFI_usTrigger();
1576 		wifi.timestamp += kWifiCycles;
1577 	}
1578 #endif
1579 
1580 	if(divider.isTriggered()) divider.exec();
1581 	if(sqrtunit.isTriggered()) sqrtunit.exec();
1582 	if(gxfifo.isTriggered()) gxfifo.exec();
1583 
1584 
1585 #define test(X,Y) if(dma_##X##_##Y .isTriggered()) dma_##X##_##Y .exec();
1586 	test(0,0); test(0,1); test(0,2); test(0,3);
1587 	test(1,0); test(1,1); test(1,2); test(1,3);
1588 #undef test
1589 #define test(X,Y) if(timer_##X##_##Y .enabled) if(timer_##X##_##Y .isTriggered()) timer_##X##_##Y .exec();
1590 	test(0,0); test(0,1); test(0,2); test(0,3);
1591 	test(1,0); test(1,1); test(1,2); test(1,3);
1592 #undef test
1593 }
1594 
1595 void execHardware_interrupts();
1596 
1597 static void saveUserInput(EMUFILE* os);
1598 static bool loadUserInput(EMUFILE* is, int version);
1599 
nds_savestate(EMUFILE * os)1600 void nds_savestate(EMUFILE* os)
1601 {
1602 	//version
1603 	write32le(3,os);
1604 
1605 	sequencer.save(os);
1606 
1607 	saveUserInput(os);
1608 
1609 	write32le(LidClosed,os);
1610 	write8le(countLid,os);
1611 }
1612 
nds_loadstate(EMUFILE * is,int size)1613 bool nds_loadstate(EMUFILE* is, int size)
1614 {
1615 	// this isn't part of the savestate loading logic, but
1616 	// don't skip the next frame after loading a savestate
1617 	frameSkipper.OmitSkip(true, true);
1618 
1619 	//read version
1620 	u32 version;
1621 	if(read32le(&version,is) != 1) return false;
1622 
1623 	if(version > 3) return false;
1624 
1625 	bool temp = true;
1626 	temp &= sequencer.load(is, version);
1627 	if(version <= 1 || !temp) return temp;
1628 	temp &= loadUserInput(is, version);
1629 
1630 	if(version < 3) return temp;
1631 
1632 	read32le(&LidClosed,is);
1633 	read8le(&countLid,is);
1634 
1635 	return temp;
1636 }
1637 
1638 #ifdef LOG_ARM9
arm9log()1639 FORCEINLINE void arm9log()
1640 {
1641 	if(dolog)
1642 	{
1643 		char dasmbuf[4096];
1644 		if(NDS_ARM9.CPSR.bits.T)
1645 			des_thumb_instructions_set[((NDS_ARM9.instruction)>>6)&1023](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);
1646 		else
1647 			des_arm_instructions_set[INDEX(NDS_ARM9.instruction)](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);
1648 
1649 #ifdef LOG_TO_FILE
1650 		if (!fp_dis9) return;
1651 #ifdef LOG_TO_FILE_REGS
1652 		fprintf(fp_dis9, "\t\t;%05d:%03d %12lld\n\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n",
1653 			currFrameCounter, nds.VCount, nds_timer,
1654 			NDS_ARM9.R[0],  NDS_ARM9.R[1],  NDS_ARM9.R[2],  NDS_ARM9.R[3],  NDS_ARM9.R[4],  NDS_ARM9.R[5],  NDS_ARM9.R[6],  NDS_ARM9.R[7],
1655 			NDS_ARM9.R[8],  NDS_ARM9.R[9],  NDS_ARM9.R[10],  NDS_ARM9.R[11],  NDS_ARM9.R[12],  NDS_ARM9.R[13],  NDS_ARM9.R[14],  NDS_ARM9.R[15],
1656 			NDS_ARM9.next_instruction, NDS_ARM9.CPSR.bits.N, NDS_ARM9.CPSR.bits.Z, NDS_ARM9.CPSR.bits.C, NDS_ARM9.CPSR.bits.V);
1657 #endif
1658 		fprintf(fp_dis9, "%s %08X\t%08X \t%s\n", NDS_ARM9.CPSR.bits.T?"THUMB":"ARM", NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);
1659 		/*if (NDS_ARM9.instruction == 0)
1660 		{
1661 			dolog = false;
1662 			INFO("Disassembler is stopped\n");
1663 		}*/
1664 #else
1665 		printf("%05d:%03d %12lld 9:%08X %08X %-30s 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\n",
1666 			currFrameCounter, nds.VCount, nds_timer,
1667 			NDS_ARM9.instruct_adr,NDS_ARM9.instruction, dasmbuf,
1668 			NDS_ARM9.R[0],  NDS_ARM9.R[1],  NDS_ARM9.R[2],  NDS_ARM9.R[3],  NDS_ARM9.R[4],  NDS_ARM9.R[5],  NDS_ARM9.R[6],  NDS_ARM9.R[7],
1669 			NDS_ARM9.R[8],  NDS_ARM9.R[9],  NDS_ARM9.R[10],  NDS_ARM9.R[11],  NDS_ARM9.R[12],  NDS_ARM9.R[13],  NDS_ARM9.R[14],  NDS_ARM9.R[15]);
1670 #endif
1671 	}
1672 }
1673 #endif
1674 
1675 #ifdef LOG_ARM7
arm7log()1676 FORCEINLINE void arm7log()
1677 {
1678 	if(dolog)
1679 	{
1680 		char dasmbuf[4096];
1681 		if(NDS_ARM7.CPSR.bits.T)
1682 			des_thumb_instructions_set[((NDS_ARM7.instruction)>>6)&1023](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);
1683 		else
1684 			des_arm_instructions_set[INDEX(NDS_ARM7.instruction)](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);
1685 #ifdef LOG_TO_FILE
1686 		if (!fp_dis7) return;
1687 #ifdef LOG_TO_FILE_REGS
1688 		fprintf(fp_dis7, "\t\t;%05d:%03d %12lld\n\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n",
1689 			currFrameCounter, nds.VCount, nds_timer,
1690 			NDS_ARM7.R[0],  NDS_ARM7.R[1],  NDS_ARM7.R[2],  NDS_ARM7.R[3],  NDS_ARM7.R[4],  NDS_ARM7.R[5],  NDS_ARM7.R[6],  NDS_ARM7.R[7],
1691 			NDS_ARM7.R[8],  NDS_ARM7.R[9],  NDS_ARM7.R[10],  NDS_ARM7.R[11],  NDS_ARM7.R[12],  NDS_ARM7.R[13],  NDS_ARM7.R[14],  NDS_ARM7.R[15],
1692 			NDS_ARM7.next_instruction, NDS_ARM7.CPSR.bits.N, NDS_ARM7.CPSR.bits.Z, NDS_ARM7.CPSR.bits.C, NDS_ARM7.CPSR.bits.V);
1693 #endif
1694 		fprintf(fp_dis7, "%s %08X\t%08X \t%s\n", NDS_ARM7.CPSR.bits.T?"THUMB":"ARM", NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);
1695 		/*if (NDS_ARM7.instruction == 0)
1696 		{
1697 			dolog = false;
1698 			INFO("Disassembler is stopped\n");
1699 		}*/
1700 #else
1701 		printf("%05d:%03d %12lld 7:%08X %08X %-30s 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\n",
1702 			currFrameCounter, nds.VCount, nds_timer,
1703 			NDS_ARM7.instruct_adr,NDS_ARM7.instruction, dasmbuf,
1704 			NDS_ARM7.R[0],  NDS_ARM7.R[1],  NDS_ARM7.R[2],  NDS_ARM7.R[3],  NDS_ARM7.R[4],  NDS_ARM7.R[5],  NDS_ARM7.R[6],  NDS_ARM7.R[7],
1705 			NDS_ARM7.R[8],  NDS_ARM7.R[9],  NDS_ARM7.R[10],  NDS_ARM7.R[11],  NDS_ARM7.R[12],  NDS_ARM7.R[13],  NDS_ARM7.R[14],  NDS_ARM7.R[15]);
1706 #endif
1707 	}
1708 }
1709 #endif
1710 
1711 //these have not been tuned very well yet.
1712 static const int kMaxWork = 4000;
1713 static const int kIrqWait = 4000;
1714 
1715 
1716 template<bool doarm9, bool doarm7>
minarmtime(s32 arm9,s32 arm7)1717 static FORCEINLINE s32 minarmtime(s32 arm9, s32 arm7)
1718 {
1719    if(doarm9)
1720    {
1721       if(doarm7)
1722          return min(arm9,arm7);
1723       return arm9;
1724    }
1725    return arm7;
1726 }
1727 
1728 #ifdef HAVE_JIT
1729 template<bool doarm9, bool doarm7, bool jit>
1730 #else
1731 template<bool doarm9, bool doarm7>
1732 #endif
armInnerLoop(const u64 nds_timer_base,const s32 s32next,s32 arm9,s32 arm7)1733 static /*donotinline*/ std::pair<s32,s32> armInnerLoop(
1734 	const u64 nds_timer_base, const s32 s32next, s32 arm9, s32 arm7)
1735 {
1736 	s32 timer = minarmtime<doarm9,doarm7>(arm9,arm7);
1737 	while(timer < s32next && !sequencer.reschedule && execute)
1738 	{
1739 		if(doarm9 && (!doarm7 || arm9 <= timer))
1740 		{
1741 			if(!NDS_ARM9.waitIRQ&&!nds.freezeBus)
1742 			{
1743 #ifdef LOG_ARM9
1744 				arm9log();
1745 #endif
1746 #ifdef DEBUG
1747 				debug();
1748 #endif
1749 #ifdef HAVE_JIT
1750 				arm9 += armcpu_exec<ARMCPU_ARM9,jit>();
1751 #else
1752 				arm9 += armcpu_exec<ARMCPU_ARM9>();
1753 #endif
1754 				#ifdef DEVELOPER
1755 					nds_debug_continuing[0] = false;
1756 				#endif
1757 			}
1758 			else
1759 			{
1760 				s32 temp = arm9;
1761 				arm9 = min(s32next, arm9 + kIrqWait);
1762 				nds.idleCycles[0] += arm9-temp;
1763 				if (gxFIFO.size < 255) nds.freezeBus &= ~1;
1764 			}
1765 		}
1766 		if(doarm7 && (!doarm9 || arm7 <= timer))
1767 		{
1768 			if(!NDS_ARM7.waitIRQ&&!nds.freezeBus)
1769 			{
1770 #ifdef LOG_ARM7
1771 				arm7log();
1772 #endif
1773 #ifdef HAVE_JIT
1774 				arm7 += (armcpu_exec<ARMCPU_ARM7,jit>()<<1);
1775 #else
1776 				arm7 += (armcpu_exec<ARMCPU_ARM7>()<<1);
1777 #endif
1778 				#ifdef DEVELOPER
1779 					nds_debug_continuing[1] = false;
1780 				#endif
1781 			}
1782 			else
1783 			{
1784 				s32 temp = arm7;
1785 				arm7 = min(s32next, arm7 + kIrqWait);
1786 				nds.idleCycles[1] += arm7-temp;
1787 				if(arm7 == s32next)
1788 				{
1789 					nds_timer = nds_timer_base + minarmtime<doarm9,false>(arm9,arm7);
1790 #ifdef HAVE_JIT
1791 					return armInnerLoop<doarm9,false,jit>(nds_timer_base, s32next, arm9, arm7);
1792 #else
1793 					return armInnerLoop<doarm9,false>(nds_timer_base, s32next, arm9, arm7);
1794 #endif
1795 				}
1796 			}
1797 		}
1798 
1799 		timer = minarmtime<doarm9,doarm7>(arm9,arm7);
1800 		nds_timer = nds_timer_base + timer;
1801 	}
1802 
1803 	return std::make_pair(arm9, arm7);
1804 }
1805 
NDS_debug_break()1806 void NDS_debug_break()
1807 {
1808 	NDS_ARM9.stalled = NDS_ARM7.stalled = 1;
1809 
1810 	//triggers an immediate exit from the cpu loop
1811 	NDS_Reschedule();
1812 }
1813 
NDS_debug_continue()1814 void NDS_debug_continue()
1815 {
1816 	NDS_ARM9.stalled = NDS_ARM7.stalled = 0;
1817 }
1818 
NDS_debug_step()1819 void NDS_debug_step()
1820 {
1821 	NDS_debug_continue();
1822 	singleStep = true;
1823 }
1824 
NDS_exec(s32 nb)1825 void NDS_exec(s32 nb)
1826 {
1827 	sequencer.nds_vblankEnded = false;
1828 
1829 	nds.cpuloopIterationCount = 0;
1830 
1831 #ifndef NDEBUG
1832 	IF_DEVELOPER(for(int i=0;i<32;i++) DEBUG_statistics.sequencerExecutionCounters[i] = 0);
1833 #endif
1834 
1835 	if(nds.sleeping)
1836 	{
1837 		//speculative code: if ANY irq happens, wake up the arm7.
1838 		//I think the arm7 program analyzes the system and may decide not to wake up
1839 		//if it is dissatisfied with the conditions
1840 		if((MMU.reg_IE[1] & MMU.gen_IF<1>()))
1841 			nds.sleeping = FALSE;
1842 	}
1843 	else
1844 	{
1845 		for(;;)
1846 		{
1847 			//trap the debug-stalled condition
1848 			#ifdef DEVELOPER
1849 				singleStep = false;
1850 				//(gdb stub doesnt yet know how to trigger these immediately by calling reschedule)
1851 				if ((NDS_ARM9.stalled || NDS_ARM7.stalled) && execute)
1852 				{
1853 					driver->EMU_DebugIdleEnter();
1854 
1855 					while((NDS_ARM9.stalled || NDS_ARM7.stalled) && execute)
1856 					{
1857 						driver->EMU_DebugIdleUpdate();
1858 						nds_debug_continuing[0] = nds_debug_continuing[1] = true;
1859 					}
1860 
1861 					driver->EMU_DebugIdleWakeUp();
1862 				}
1863 			#endif
1864 
1865 			nds.cpuloopIterationCount++;
1866 			sequencer.execHardware();
1867 
1868 			//break out once per frame
1869 			if(sequencer.nds_vblankEnded) break;
1870 			//it should be benign to execute execHardware in the next frame,
1871 			//since there won't be anything for it to do (everything should be scheduled in the future)
1872 
1873 			//bail in case the system halted
1874 			if(!execute) break;
1875 
1876 			execHardware_interrupts();
1877 
1878 			//find next work unit:
1879 			u64 next = sequencer.findNext();
1880 			next = min(next,nds_timer+kMaxWork); //lets set an upper limit for now
1881 
1882 			//printf("%d\n",(next-nds_timer));
1883 
1884 			sequencer.reschedule = false;
1885 
1886 			//cast these down to 32bits so that things run faster on 32bit procs
1887 			u64 nds_timer_base = nds_timer;
1888 			s32 arm9 = (s32)(nds_arm9_timer-nds_timer);
1889 			s32 arm7 = (s32)(nds_arm7_timer-nds_timer);
1890 			s32 s32next = (s32)(next-nds_timer);
1891 
1892 			#ifdef DEVELOPER
1893 				if(singleStep)
1894 				{
1895 					s32next = 1;
1896 				}
1897 			#endif
1898 
1899 #ifdef HAVE_JIT
1900 			std::pair<s32,s32> arm9arm7 = CommonSettings.use_jit
1901 				? armInnerLoop<true,true,true>(nds_timer_base,s32next,arm9,arm7)
1902 				: armInnerLoop<true,true,false>(nds_timer_base,s32next,arm9,arm7);
1903 #else
1904 				std::pair<s32,s32> arm9arm7 = armInnerLoop<true,true>(nds_timer_base,s32next,arm9,arm7);
1905 #endif
1906 
1907 			#ifdef DEVELOPER
1908 				if(singleStep)
1909 				{
1910 					NDS_ARM9.stalled = NDS_ARM7.stalled = 1;
1911 				}
1912 			#endif
1913 
1914 			arm9 = arm9arm7.first;
1915 			arm7 = arm9arm7.second;
1916 			nds_arm7_timer = nds_timer_base+arm7;
1917 			nds_arm9_timer = nds_timer_base+arm9;
1918 
1919 #ifndef NDEBUG
1920 			//what we find here is dependent on the timing constants above
1921 			//if(nds_timer>next && (nds_timer-next)>22)
1922 			//	printf("curious. please report: over by %d\n",(int)(nds_timer-next));
1923 #endif
1924 
1925 			//if we were waiting for an irq, don't wait too long:
1926 			//let's re-analyze it after this hardware event (this rolls back a big burst of irq waiting which may have been interrupted by a resynch)
1927 			if(NDS_ARM9.waitIRQ)
1928 			{
1929 				nds.idleCycles[0] -= (s32)(nds_arm9_timer-nds_timer);
1930 				nds_arm9_timer = nds_timer;
1931 			}
1932 			if(NDS_ARM7.waitIRQ)
1933 			{
1934 				nds.idleCycles[1] -= (s32)(nds_arm7_timer-nds_timer);
1935 				nds_arm7_timer = nds_timer;
1936 			}
1937 		}
1938 	}
1939 
1940 	currFrameCounter++;
1941 #ifndef NDEBUG
1942 	DEBUG_Notify.NextFrame();
1943 #endif
1944 	if (cheats)
1945 		cheats->process();
1946 }
1947 
execHardware_interrupts_core()1948 template<int PROCNUM> static void execHardware_interrupts_core()
1949 {
1950 	u32 IF = MMU.gen_IF<PROCNUM>();
1951 	u32 IE = MMU.reg_IE[PROCNUM];
1952 	u32 masked = IF & IE;
1953 	if(ARMPROC.halt_IE_and_IF && masked)
1954 	{
1955 		ARMPROC.halt_IE_and_IF = FALSE;
1956 		ARMPROC.waitIRQ = FALSE;
1957 	}
1958 
1959 	if(masked && MMU.reg_IME[PROCNUM] && !ARMPROC.CPSR.bits.I)
1960 	{
1961 		//printf("Executing IRQ on procnum %d with IF = %08X and IE = %08X\n",PROCNUM,IF,IE);
1962 		armcpu_irqException(&ARMPROC);
1963 	}
1964 }
1965 
execHardware_interrupts()1966 void execHardware_interrupts()
1967 {
1968 	execHardware_interrupts_core<ARMCPU_ARM9>();
1969 	execHardware_interrupts_core<ARMCPU_ARM7>();
1970 }
1971 
1972 static void resetUserInput();
1973 
PrepareBiosARM7()1974 static void PrepareBiosARM7()
1975 {
1976 	//begin with the bios unloaded
1977 	NDS_ARM7.BIOS_loaded = false;
1978 	memset(MMU.ARM7_BIOS, 0, sizeof(MMU.ARM7_BIOS));
1979 
1980 	if(CommonSettings.UseExtBIOS == true)
1981 	{
1982 		//read arm7 bios from inputfile and flag it if it succeeds
1983 		FILE *arm7inf = fopen(CommonSettings.ARM7BIOS,"rb");
1984 		if (arm7inf)
1985 		{
1986 			if (fread(MMU.ARM7_BIOS,1,16384,arm7inf) == 16384)
1987 				NDS_ARM7.BIOS_loaded = true;
1988 			fclose(arm7inf);
1989 		}
1990 	}
1991 
1992 	//choose to use SWI emulation or routines from bios
1993 	if((CommonSettings.SWIFromBIOS) && (NDS_ARM7.BIOS_loaded))
1994 	{
1995 		NDS_ARM7.swi_tab = 0;
1996 
1997 		//if we used routines from bios, apply patches
1998 		if (CommonSettings.PatchSWI3)
1999 		{
2000 			//[3801] SUB R0, #1 -> [4770] BX LR
2001 			T1WriteWord(MMU.ARM7_BIOS,0x2F08, 0x4770);
2002 		}
2003 	}
2004 	else
2005 		NDS_ARM7.swi_tab = ARM_swi_tab[ARMCPU_ARM7];
2006 
2007 	if(NDS_ARM7.BIOS_loaded)
2008 	{
2009 #ifdef DEBUG
2010 		INFO("ARM7 BIOS load: %s.\n", NDS_ARM7.BIOS_loaded?"OK":"FAILED");
2011 #endif
2012 	}
2013 	else
2014 	{
2015 		//fake bios content, critical to normal operations, since we dont have a real bios.
2016 
2017 		T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xEAFFFFFE); //B 00000000 (reset: infinite loop) (originally: 0xE25EF002 - SUBS PC, LR, #2
2018 		T1WriteLong(MMU.ARM7_BIOS, 0x0004, 0xEAFFFFFE); //B 00000004 (undefined instruction: infinite loop)
2019 		T1WriteLong(MMU.ARM7_BIOS, 0x0008, 0xEAFFFFFE); //B 00000280 (SWI: infinite loop [since we will be HLEing the SWI routines])
2020 		T1WriteLong(MMU.ARM7_BIOS, 0x000C, 0xEAFFFFFE); //B 0000000C (prefetch abort: infinite loop)
2021 		T1WriteLong(MMU.ARM7_BIOS, 0x0010, 0xEAFFFFFE); //B 00000010 (data abort: infinite loop)
2022 		T1WriteLong(MMU.ARM7_BIOS, 0x0018, 0xEA000000); //B 00000020 (IRQ: branch to handler)
2023 		T1WriteLong(MMU.ARM7_BIOS, 0x001C, 0xEAFFFFFE); //B 0000001C (FIQ vector: infinite loop)
2024 		//IRQ handler
2025 		T1WriteLong(MMU.ARM7_BIOS, 0x0020, 0xE92D500F); //STMDB SP!, {R0-R3,R12,LR}
2026 		T1WriteLong(MMU.ARM7_BIOS, 0x0024, 0xE3A00301); //MOV R0, #4000000
2027 		T1WriteLong(MMU.ARM7_BIOS, 0x0028, 0xE28FE000); //ADD LR, PC, #0
2028 		T1WriteLong(MMU.ARM7_BIOS, 0x002C, 0xE510F004); //LDR PC, [R0, -#4]
2029 		T1WriteLong(MMU.ARM7_BIOS, 0x0030, 0xE8BD500F); //LDMIA SP!, {R0-R3,R12,LR}
2030 		T1WriteLong(MMU.ARM7_BIOS, 0x0034, 0xE25EF004); //SUBS PC, LR, #4
2031 	}
2032 }
2033 
PrepareBiosARM9()2034 static void PrepareBiosARM9()
2035 {
2036 	//begin with the bios unloaded
2037 	memset(MMU.ARM9_BIOS, 0, sizeof(MMU.ARM9_BIOS));
2038 	NDS_ARM9.BIOS_loaded = false;
2039 
2040 	if(CommonSettings.UseExtBIOS == true)
2041 	{
2042 		//read arm9 bios from inputfile and flag it if it succeeds
2043 		FILE* arm9inf = fopen(CommonSettings.ARM9BIOS,"rb");
2044 		if (arm9inf)
2045 		{
2046 			if (fread(MMU.ARM9_BIOS,1,4096,arm9inf) == 4096)
2047 				NDS_ARM9.BIOS_loaded = true;
2048 			fclose(arm9inf);
2049 		}
2050 	}
2051 
2052 	//choose to use SWI emulation or routines from bios
2053 	if((CommonSettings.SWIFromBIOS) && (NDS_ARM9.BIOS_loaded))
2054 	{
2055 		NDS_ARM9.swi_tab = 0;
2056 
2057 		//if we used routines from bios, apply patches
2058 		//[3801] SUB R0, #1 -> [4770] BX LR
2059 		if (CommonSettings.PatchSWI3)
2060 			T1WriteWord(MMU.ARM9_BIOS, 0x07CC, 0x4770);
2061 	}
2062 	else NDS_ARM9.swi_tab = ARM_swi_tab[ARMCPU_ARM9];
2063 
2064 	if(NDS_ARM9.BIOS_loaded)
2065 	{
2066 #ifdef DEBUG
2067 		INFO("ARM9 BIOS load: %s.\n", NDS_ARM9.BIOS_loaded?"OK":"FAILED");
2068 #endif
2069 	}
2070 	else
2071 	{
2072 		//fake bios content, critical to normal operations, since we dont have a real bios.
2073 		//it'd be cool if we could write this in some kind of assembly language, inline or otherwise, without some bulky dependencies
2074 		//perhaps we could build it with devkitarm? but thats bulky (offline) dependencies, to be sure..
2075 
2076 		//reminder: bios chains data abort to fast irq
2077 
2078 		//exception vectors:
2079 		T1WriteLong(MMU.ARM9_BIOS, 0x0000, 0xEAFFFFFE);		// (infinite loop for) Reset !!!
2080 		//T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEAFFFFFE);		// (infinite loop for) Undefined instruction
2081 		T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEA000004);		// Undefined instruction -> Fast IRQ (just guessing)
2082 		T1WriteLong(MMU.ARM9_BIOS, 0x0008, 0xEA00009C);		// SWI -> ?????
2083 		T1WriteLong(MMU.ARM9_BIOS, 0x000C, 0xEAFFFFFE);		// (infinite loop for) Prefetch Abort
2084 		T1WriteLong(MMU.ARM9_BIOS, 0x0010, 0xEA000001);		// Data Abort -> Fast IRQ
2085 		T1WriteLong(MMU.ARM9_BIOS, 0x0014, 0x00000000);		// Reserved
2086 		T1WriteLong(MMU.ARM9_BIOS, 0x0018, 0xEA000095);		// Normal IRQ -> 0x0274
2087 		T1WriteLong(MMU.ARM9_BIOS, 0x001C, 0xEA00009D);		// Fast IRQ -> 0x0298
2088 
2089 		//copy the logo content into the bios - Pokemon Platinum uses this in Pal Park trade
2090 		//it compares the logo from the arm9 bios to the logo in the GBA header.
2091 		//NOTE: in the unlikely event that the valid header is missing from the gameInfo, we'd be doing wrong here.
2092 		//      however, its nice not to have the logo embedded here.
2093 		//      TODO - take a CRC of the logo, check vs logoCRC16, and a hardcoded value, to make sure all is in order--report error if not
2094 		memcpy(&MMU.ARM9_BIOS[0x20], &gameInfo.header.logo[0], 0x9C);
2095 		T1WriteWord(MMU.ARM9_BIOS, 0x20 + 0x9C,  gameInfo.header.logoCRC16);
2096 		//... and with that we are at 0xBC:
2097 
2098 		//(now what goes in this gap?? nothing we need, i guess)
2099 
2100 		//IRQ handler: get dtcm address and jump to a vector in it
2101 		T1WriteLong(MMU.ARM9_BIOS, 0x0274, 0xE92D500F); //STMDB SP!, {R0-R3,R12,LR}
2102 		T1WriteLong(MMU.ARM9_BIOS, 0x0278, 0xEE190F11); //MRC CP15, 0, R0, CR9, CR1, 0
2103 		T1WriteLong(MMU.ARM9_BIOS, 0x027C, 0xE1A00620); //MOV R0, R0, LSR #C
2104 		T1WriteLong(MMU.ARM9_BIOS, 0x0280, 0xE1A00600); //MOV R0, R0, LSL #C
2105 		T1WriteLong(MMU.ARM9_BIOS, 0x0284, 0xE2800C40); //ADD R0, R0, #4000
2106 		T1WriteLong(MMU.ARM9_BIOS, 0x0288, 0xE28FE000); //ADD LR, PC, #0
2107 		T1WriteLong(MMU.ARM9_BIOS, 0x028C, 0xE510F004); //LDR PC, [R0, -#4]
2108 
2109 		//????
2110 		T1WriteLong(MMU.ARM9_BIOS, 0x0290, 0xE8BD500F); //LDMIA SP!, {R0-R3,R12,LR}
2111 		T1WriteLong(MMU.ARM9_BIOS, 0x0294, 0xE25EF004); //SUBS PC, LR, #4
2112 
2113 		//-------
2114 		//FIQ and abort exception handler
2115 		//TODO - this code is copied from the bios. refactor it
2116 		//friendly reminder: to calculate an immediate offset: encoded = (desired_address-cur_address-8)
2117 
2118 		T1WriteLong(MMU.ARM9_BIOS, 0x0298, 0xE10FD000); //MRS SP, CPSR
2119 		T1WriteLong(MMU.ARM9_BIOS, 0x029C, 0xE38DD0C0); //ORR SP, SP, #C0
2120 
2121 		T1WriteLong(MMU.ARM9_BIOS, 0x02A0, 0xE12FF00D); //MSR CPSR_fsxc, SP
2122 		T1WriteLong(MMU.ARM9_BIOS, 0x02A4, 0xE59FD000 | (0x2D4-0x2A4-8)); //LDR SP, [FFFF02D4]
2123 		T1WriteLong(MMU.ARM9_BIOS, 0x02A8, 0xE28DD001); //ADD SP, SP, #1
2124 		T1WriteLong(MMU.ARM9_BIOS, 0x02AC, 0xE92D5000); //STMDB SP!, {R12,LR}
2125 
2126 		T1WriteLong(MMU.ARM9_BIOS, 0x02B0, 0xE14FE000); //MRS LR, SPSR
2127 		T1WriteLong(MMU.ARM9_BIOS, 0x02B4, 0xEE11CF10); //MRC CP15, 0, R12, CR1, CR0, 0
2128 		T1WriteLong(MMU.ARM9_BIOS, 0x02B8, 0xE92D5000); //STMDB SP!, {R12,LR}
2129 		T1WriteLong(MMU.ARM9_BIOS, 0x02BC, 0xE3CCC001); //BIC R12, R12, #1
2130 
2131 		T1WriteLong(MMU.ARM9_BIOS, 0x02C0, 0xEE01CF10); //MCR CP15, 0, R12, CR1, CR0, 0
2132 		T1WriteLong(MMU.ARM9_BIOS, 0x02C4, 0xE3CDC001); //BIC R12, SP, #1
2133 		T1WriteLong(MMU.ARM9_BIOS, 0x02C8, 0xE59CC010); //LDR R12, [R12, #10]
2134 		T1WriteLong(MMU.ARM9_BIOS, 0x02CC, 0xE35C0000); //CMP R12, #0
2135 
2136 		T1WriteLong(MMU.ARM9_BIOS, 0x02D0, 0x112FFF3C); //BLXNE R12
2137 		T1WriteLong(MMU.ARM9_BIOS, 0x02D4, 0x027FFD9C); //0x027FFD9C
2138 		//---------
2139 	}
2140 }
2141 
JumbleMemory()2142 static void JumbleMemory() { }
2143 
PrepareLogfiles()2144 static void PrepareLogfiles()
2145 {
2146 #ifdef LOG_ARM7
2147 	if (fp_dis7 != NULL)
2148 	{
2149 		fclose(fp_dis7);
2150 		fp_dis7 = NULL;
2151 	}
2152 	fp_dis7 = fopen("D:\\desmume_dis7.asm", "w");
2153 #endif
2154 
2155 #ifdef LOG_ARM9
2156 	if (fp_dis9 != NULL)
2157 	{
2158 		fclose(fp_dis9);
2159 		fp_dis9 = NULL;
2160 	}
2161 	fp_dis9 = fopen("D:\\desmume_dis9.asm", "w");
2162 #endif
2163 }
2164 
NDS_LegitBoot()2165 bool NDS_LegitBoot()
2166 {
2167 	#ifdef HAVE_JIT
2168 		//hack for firmware boot in JIT mode.
2169 		//we know that it takes certain jit parameters to successfully boot the firmware.
2170 		//CRAZYMAX: is it safe to accept anything smaller than 12?
2171 		CommonSettings.jit_max_block_size = std::min(CommonSettings.jit_max_block_size,12U);
2172 	#endif
2173 
2174 	//partially clobber the loaded firmware with the user settings from DFC
2175 	firmware->loadSettings();
2176 
2177 	//since firmware only boots encrypted roms, we have to make sure it's encrypted first
2178 	//this has not been validated on big endian systems. it almost positively doesn't work.
2179 	if (gameInfo.header.CRC16 != 0)
2180 		EncryptSecureArea((u8*)&gameInfo.header, (u8*)gameInfo.secureArea);
2181 
2182 	//boot processors from their bios entrypoints
2183 	armcpu_init(&NDS_ARM7, 0x00000000);
2184 	armcpu_init(&NDS_ARM9, 0xFFFF0000);
2185 
2186 	return true;
2187 }
2188 
2189 //the fake firmware boot-up process
NDS_FakeBoot()2190 bool NDS_FakeBoot()
2191 {
2192 	NDS_header * header = NDS_getROMHeader();
2193 
2194 #ifndef NDEBUG
2195 	DEBUG_reset();
2196 #endif
2197 
2198 	if (!header) return false;
2199 
2200 	nds.isFakeBooted = true;
2201 
2202 	//since we're bypassing the code to decrypt the secure area, we need to make sure its decrypted first
2203 	//this has not been validated on big endian systems. it almost positively doesn't work.
2204 	if (gameInfo.header.CRC16 != 0)
2205 	{
2206 		bool okRom = DecryptSecureArea((u8*)&gameInfo.header, (u8*)gameInfo.secureArea);
2207 
2208 		if(!okRom) {
2209 			printf("Specified file is not a valid rom\n");
2210 			return false;
2211 		}
2212 	}
2213 
2214 	//bios (or firmware) sets this default, which is generally not important for retail games but some homebrews are depending on
2215 	_MMU_write08<ARMCPU_ARM9>(REG_WRAMCNT,3);
2216 
2217 	//EDIT - whats this firmware and how is it relating to the dummy firmware below
2218 	//how do these even get used? what is the purpose of unpack and why is it not used by the firmware boot process?
2219 	if (CommonSettings.UseExtFirmware && firmware->loaded())
2220 	{
2221 		firmware->unpack();
2222 		firmware->loadSettings();
2223 	}
2224 
2225 	// Create the dummy firmware
2226 	//EDIT - whats dummy firmware and how is relating to the above?
2227 	//it seems to be emplacing basic firmware data into MMU.fw.data
2228 	NDS_CreateDummyFirmware(&CommonSettings.fw_config);
2229 
2230 	//firmware loads the game card arm9 and arm7 programs as specified in rom header
2231 	{
2232 		bool hasSecureArea = ((gameInfo.romType == ROM_NDS) && (gameInfo.header.CRC16 != 0));
2233 		//copy the arm9 program to the address specified by rom header
2234 		u32 src = header->ARM9src;
2235 		u32 dst = header->ARM9cpy;
2236 		for(u32 i = 0; i < header->ARM9binSize; i+=4)
2237 		{
2238 			u32 tmp = (hasSecureArea && ((src >= 0x4000) && (src < 0x8000)))?LE_TO_LOCAL_32(*(u32*)(gameInfo.secureArea + (src - 0x4000))):gameInfo.readROM(src);
2239 
2240 			_MMU_write32<ARMCPU_ARM9>(dst, tmp);
2241 
2242 			dst += 4;
2243 			src += 4;
2244 		}
2245 
2246 		//copy the arm7 program to the address specified by rom header
2247 		src = header->ARM7src;
2248 		dst = header->ARM7cpy;
2249 		for(u32 i = 0; i < header->ARM7binSize; i+=4)
2250 		{
2251 			_MMU_write32<ARMCPU_ARM7>(dst, gameInfo.readROM(src));
2252 
2253 			dst += 4;
2254 			src += 4;
2255 		}
2256 	}
2257 
2258 	//bios does this (thats weird, though. shouldnt it get changed when the card is swapped in the firmware menu?
2259 	//right now our firmware menu isnt detecting any change to the card.
2260 	//are some games depending on it being written here? please document.
2261 	//_MMU_write16<ARMCPU_ARM9>(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E));
2262 
2263 	//firmware sets up a copy of the firmware user settings in memory.
2264 	//TBD - this code is really clunky
2265 	//it seems to be copying the MMU.fw.data data into RAM in the user memory stash locations
2266 	u8 temp_buffer[NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT];
2267 	if ( copy_firmware_user_data( temp_buffer, MMU.fw.data)) {
2268 		for ( int fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; fw_index++)
2269 			_MMU_write08<ARMCPU_ARM9>(0x027FFC80 + fw_index, temp_buffer[fw_index]);
2270 	}
2271 
2272 	//something copies the whole header to Main RAM 0x27FFE00 on startup. (http://nocash.emubase.de/gbatek.htm#dscartridgeheader)
2273 	//once upon a time this copied 0x90 more. this was thought to be wrong, and changed.
2274 	if(nds.Is_DSI())
2275 	{
2276 		//dsi needs this copied later in memory. there are probably a number of things that  get copied to a later location in memory.. thats where the NDS consoles tend to stash stuff.
2277 		for (int i = 0; i < (0x170); i+=4)
2278 			_MMU_write32<ARMCPU_ARM9>(0x027FFE00 + i, gameInfo.readROM(i));
2279 	}
2280 	else
2281 	{
2282 		for (int i = 0; i < (0x170); i+=4)
2283 			_MMU_write32<ARMCPU_ARM9>(0x027FFE00 + i, gameInfo.readROM(i));
2284 	}
2285 
2286 	//the firmware will be booting to these entrypoint addresses via BX (well, the arm9 at least; is unverified for the arm7)
2287 	armcpu_init(&NDS_ARM7, header->ARM7exe);
2288 	armcpu_init(&NDS_ARM9, header->ARM9exe);
2289 
2290 	//firmware sets REG_POSTFLG to the value indicating post-firmware status
2291 	MMU.ARM9_REG[0x300] = 1;
2292 	MMU.ARM7_REG[0x300] = 1;
2293 
2294 	//firmware makes system think it's booted from card -- EXTREMELY IMPORTANT!!! This is actually checked by some things. (which things?) Thanks to cReDiAr
2295 	_MMU_write08<ARMCPU_ARM7>(0x02FFFC40,0x1); //<zero> removed redundant write to ARM9, this is going to shared main memory. But one has to wonder why r3478 was made which corrected a typo resulting in only ARMCPU_ARM7 getting used.
2296 
2297 	//the chipId is read several times
2298 	//for some reason, each of those reads get stored here.
2299 	_MMU_write32<ARMCPU_ARM7>(0x027FF800, gameInfo.chipID);		//1st chipId
2300 	_MMU_write32<ARMCPU_ARM7>(0x027FF804, gameInfo.chipID);		//2nd (secure) chipId
2301 	_MMU_write32<ARMCPU_ARM7>(0x027FFC00, gameInfo.chipID);		//3rd (secure) chipId
2302 
2303 	// Write the header checksum to memory
2304 	_MMU_write16<ARMCPU_ARM9>(0x027FF808, gameInfo.header.headerCRC16);
2305 
2306 	//bitbox 4k demo is so stripped down it relies on default stack values
2307 	//otherwise the arm7 will crash before making a sound
2308 	//(these according to gbatek softreset bios docs)
2309 	NDS_ARM7.R13_svc = 0x0380FFDC;
2310 	NDS_ARM7.R13_irq = 0x0380FFB0;
2311 	NDS_ARM7.R13_usr = 0x0380FF00;
2312 	NDS_ARM7.R[13] = NDS_ARM7.R13_usr;
2313 	//and let's set these for the arm9 while we're at it, though we have no proof
2314 	NDS_ARM9.R13_svc = 0x00803FC0;
2315 	NDS_ARM9.R13_irq = 0x00803FA0;
2316 	NDS_ARM9.R13_usr = 0x00803EC0;
2317 	NDS_ARM9.R13_abt = NDS_ARM9.R13_usr; //?????
2318 	//I think it is wrong to take gbatek's "SYS" and put it in USR--maybe USR doesnt matter.
2319 	//i think SYS is all the misc modes. please verify by setting nonsensical stack values for USR here
2320 	NDS_ARM9.R[13] = NDS_ARM9.R13_usr;
2321 	//n.b.: im not sure about all these, I dont know enough about arm9 svc/irq/etc modes
2322 	//and how theyre named in desmume to match them up correctly. i just guessed.
2323 
2324 	//--------------------------------
2325 	//setup the homebrew argv
2326 	//this is useful for nitrofs apps which are emulating themselves via cflash
2327 	//struct __argv {
2328 	//	int argvMagic;		//!< argv magic number, set to 0x5f617267 ('_arg') if valid
2329 	//	char *commandLine;	//!< base address of command line, set of null terminated strings
2330 	//	int length;			//!< total length of command line
2331 	//	int argc;			//!< internal use, number of arguments
2332 	//	char **argv;		//!< internal use, argv pointer
2333 	//};
2334 	std::string rompath = "fat:/" + path.RomName;
2335 	const u32 kCommandline = 0x027E0000;
2336 	//const u32 kCommandline = 0x027FFF84;
2337 
2338 	//homebrew-related stuff.
2339 	//its safe to put things in this position.. apparently nothing important is here.
2340 	//however, some games could be checking them as an anti-desmume measure, so we might have to control it with slot-1 settings to suggest booting a homebrew app
2341 	//perhaps we could automatically boot homebrew to an R4-like device.
2342 	_MMU_write32<ARMCPU_ARM9>(0x02FFFE70, 0x5f617267);
2343 	_MMU_write32<ARMCPU_ARM9>(0x02FFFE74, kCommandline); //(commandline starts here)
2344 	_MMU_write32<ARMCPU_ARM9>(0x02FFFE78, rompath.size()+1);
2345 	//0x027FFF7C (argc)
2346 	//0x027FFF80 (argv)
2347 	for(size_t i=0;i<rompath.size();i++)
2348 		_MMU_write08<ARMCPU_ARM9>(kCommandline+i, rompath[i]);
2349 	_MMU_write08<ARMCPU_ARM9>(kCommandline+rompath.size(), 0);
2350 	//--------------------------------
2351 
2352 	//Call the card post_fakeboot hook to perform additional initialization
2353 	slot1_device->post_fakeboot(ARMCPU_ARM9);
2354 	slot1_device->post_fakeboot(ARMCPU_ARM7);
2355 
2356 	delete header;
2357 	return true;
2358 }
2359 
NDS_Reset()2360 void NDS_Reset()
2361 {
2362 	PrepareLogfiles();
2363 
2364    currFrameCounter = 0;
2365 
2366 	resetUserInput();
2367 
2368 
2369 	singleStep = false;
2370 	nds_debug_continuing[0] = nds_debug_continuing[1] = false;
2371 	nds.sleeping = FALSE;
2372 	nds.cardEjected = FALSE;
2373 	nds.freezeBus = 0;
2374 	nds.power1.lcd = nds.power1.gpuMain = nds.power1.gfx3d_render = nds.power1.gfx3d_geometry = nds.power1.gpuSub = nds.power1.dispswap = 1;
2375 	nds.power2.speakers = 1;
2376 	nds.power2.wifi = 0;
2377 	nds.wifiCycle = 0;
2378 	memset(nds.timerCycle, 0, sizeof(u64) * 2 * 4);
2379 	nds.old = 0;
2380 	nds.scr_touchX = nds.scr_touchY = nds.adc_touchX = nds.adc_touchY = 0;
2381 	nds.isTouch = 0;
2382 	nds.isFakeBooted = false;
2383 	nds.paddle = 0;
2384 	nds.ConsoleType = CommonSettings.ConsoleType;
2385 	nds._DebugConsole = CommonSettings.DebugConsole;
2386 	nds.ensataEmulation = CommonSettings.EnsataEmulation;
2387 	nds.stylusJitter = CommonSettings.StylusJitter;
2388 	nds.ensataHandshake = ENSATA_HANDSHAKE_none;
2389 	nds.ensataIpcSyncCounter = 0;
2390 	nds_timer = 0;
2391 	nds_arm9_timer = 0;
2392 	nds_arm7_timer = 0;
2393 	LidClosed = FALSE;
2394 	countLid = 0;
2395 
2396 	MMU_Reset();
2397 	SetupMMU(nds.Is_DebugConsole(),nds.Is_DSI());
2398 	JumbleMemory();
2399 
2400 	#ifdef HAVE_JIT
2401 		arm_jit_reset(CommonSettings.use_jit);
2402 	#endif
2403 
2404 
2405 	//initialize CP15 specially for this platform
2406 	//TODO - how much of this is necessary for firmware boot?
2407 	//(only ARM9 has CP15)
2408 	reconstruct(&cp15);
2409 	MMU.ARM9_RW_MODE = BIT7(cp15.ctrl);
2410 	NDS_ARM9.intVector = 0xFFFF0000 * (BIT13(cp15.ctrl));
2411 	NDS_ARM9.LDTBit = !BIT15(cp15.ctrl); //TBit
2412 
2413 	PrepareBiosARM7();
2414 	PrepareBiosARM9();
2415 
2416 	if (firmware)
2417 	{
2418 		delete firmware;
2419 		firmware = NULL;
2420 	}
2421 
2422 	firmware = new CFIRMWARE();
2423 	firmware->load();
2424 
2425 	//we will allow a proper firmware boot, if:
2426 	//1. we have the ARM7 and ARM9 bioses (its doubtful that our HLE bios implement the necessary functions)
2427 	//2. firmware is available
2428 	//3. user has requested booting from firmware
2429 	bool canBootFromFirmware = (NDS_ARM7.BIOS_loaded && NDS_ARM9.BIOS_loaded && CommonSettings.BootFromFirmware && firmware->loaded());
2430 	bool bootResult = false;
2431 	if(canBootFromFirmware)
2432 		bootResult = NDS_LegitBoot();
2433 	else
2434 		bootResult = NDS_FakeBoot();
2435 
2436 	// Init calibration info
2437 	memcpy(&TSCal, firmware->getTouchCalibrate(), sizeof(TSCalInfo));
2438 
2439    GPU->Reset();
2440 
2441 	WIFI_Reset();
2442 	memcpy(FW_Mac, (MMU.fw.data + 0x36), 6);
2443 
2444 	SPU_DeInit();
2445 	SPU_ReInit(!canBootFromFirmware && bootResult);
2446 
2447 	//this needs to happen last, pretty much, since it establishes the correct scheduling state based on all of the above initialization
2448 	initSchedule();
2449 }
2450 
2451 //convert a 12.4 screen coordinate to an ADC value.
2452 //the desmume host system will track the screen coordinate, but the hardware should be receiving the raw ADC values.
2453 //so we'll need to use this to simulate the ADC values corresponding to the desired screen coords, based on the current TSC calibrations
NDS_getADCTouchPosX(int scrX_lsl4)2454 u16 NDS_getADCTouchPosX(int scrX_lsl4)
2455 {
2456 	scrX_lsl4 >>= 4;
2457 	int rv = ((scrX_lsl4 - TSCal.scr.x1 + 1) * TSCal.adc.width) / TSCal.scr.width + TSCal.adc.x1;
2458 	rv = min(0xFFF, max(0, rv));
2459 	return (u16)(rv);
2460 }
NDS_getADCTouchPosY(int scrY_lsl4)2461 u16 NDS_getADCTouchPosY(int scrY_lsl4)
2462 {
2463 	scrY_lsl4 >>= 4;
2464 	int rv = ((scrY_lsl4 - TSCal.scr.y1 + 1) * TSCal.adc.height) / TSCal.scr.height + TSCal.adc.y1;
2465 	rv = min(0xFFF, max(0, rv));
2466 	return (u16)(rv);
2467 }
2468 
2469 static UserInput rawUserInput = {}; // requested input, generally what the user is physically pressing
2470 static UserInput finalUserInput = {}; // what gets sent to the game and possibly recorded
2471 
NDS_getRawUserInput()2472 const UserInput& NDS_getRawUserInput()
2473 {
2474 	return rawUserInput;
2475 }
2476 
NDS_getProcessingUserInput()2477 UserInput& NDS_getProcessingUserInput()
2478 {
2479 	return rawUserInput;
2480 }
2481 
NDS_getFinalUserInput()2482 const UserInput& NDS_getFinalUserInput()
2483 {
2484 	return finalUserInput;
2485 }
2486 
2487 
saveUserInput(EMUFILE * os,UserInput & input)2488 static void saveUserInput(EMUFILE* os, UserInput& input)
2489 {
2490 	os->fwrite((const char*)input.buttons.array, 14);
2491 	writebool(input.touch.isTouch, os);
2492 	write16le(input.touch.touchX, os);
2493 	write16le(input.touch.touchY, os);
2494 	write32le(input.mic.micButtonPressed, os);
2495 }
loadUserInput(EMUFILE * is,UserInput & input,int version)2496 static bool loadUserInput(EMUFILE* is, UserInput& input, int version)
2497 {
2498 	is->fread((char*)input.buttons.array, 14);
2499 	readbool(&input.touch.isTouch, is);
2500 	read16le(&input.touch.touchX, is);
2501 	read16le(&input.touch.touchY, is);
2502 	read32le(&input.mic.micButtonPressed, is);
2503 	return true;
2504 }
resetUserInput(UserInput & input)2505 static void resetUserInput(UserInput& input)
2506 {
2507 	memset(&input, 0, sizeof(UserInput));
2508 }
2509 // (userinput is kind of a misnomer, e.g. finalUserInput has to mirror nds.pad, nds.touchX, etc.)
saveUserInput(EMUFILE * os)2510 static void saveUserInput(EMUFILE* os)
2511 {
2512 	saveUserInput(os, finalUserInput);
2513 	saveUserInput(os, rawUserInput); // saved in case a savestate is made during input processing (which Lua could do if nothing else)
2514    bool validToProcessInput = true;
2515 	writebool(validToProcessInput, os);
2516 	for(int i = 0; i < 14; i++)
2517 		write32le(0, os); // saved to make autofire more tolerable to use with re-recording
2518 }
loadUserInput(EMUFILE * is,int version)2519 static bool loadUserInput(EMUFILE* is, int version)
2520 {
2521 	bool rv = true;
2522    bool validToProcessInput = true;
2523 	rv &= loadUserInput(is, finalUserInput, version);
2524 	rv &= loadUserInput(is, rawUserInput, version);
2525 	readbool(&validToProcessInput, is);
2526    u32 j = 0;
2527 	for(int i = 0; i < 14; i++)
2528 		read32le((u32*)&j, is);
2529 	return rv;
2530 }
resetUserInput()2531 static void resetUserInput()
2532 {
2533 	resetUserInput(finalUserInput);
2534 }
2535 
NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,bool X,bool W,bool E,bool G,bool F)2536 void NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,bool X,bool W,bool E,bool G, bool F)
2537 {
2538 	UserButtons& rawButtons = rawUserInput.buttons;
2539 	rawButtons.R = R;
2540 	rawButtons.L = L;
2541 	rawButtons.D = D;
2542 	rawButtons.U = U;
2543 	rawButtons.T = T;
2544 	rawButtons.S = S;
2545 	rawButtons.B = B;
2546 	rawButtons.A = A;
2547 	rawButtons.Y = Y;
2548 	rawButtons.X = X;
2549 	rawButtons.W = W;
2550 	rawButtons.E = E;
2551 	rawButtons.G = G;
2552 	rawButtons.F = F;
2553 }
NDS_setTouchPos(u16 x,u16 y,u16 scale)2554 void NDS_setTouchPos(u16 x, u16 y, u16 scale)
2555 {
2556 	rawUserInput.touch.touchX = (x/scale)<<4;
2557 	rawUserInput.touch.touchY = (y/scale)<<4;
2558 	rawUserInput.touch.isTouch = true;
2559 
2560    nds.stylusJitter = CommonSettings.StylusJitter;
2561 }
2562 
NDS_releaseTouch(void)2563 void NDS_releaseTouch(void)
2564 {
2565 	rawUserInput.touch.touchX = 0;
2566 	rawUserInput.touch.touchY = 0;
2567 	rawUserInput.touch.isTouch = false;
2568 }
NDS_setMic(bool pressed)2569 void NDS_setMic(bool pressed)
2570 {
2571 	rawUserInput.mic.micButtonPressed = (pressed ? TRUE : FALSE);
2572 }
2573 
2574 
NDS_applyFinalInput()2575 static void NDS_applyFinalInput()
2576 {
2577 	const UserInput& input = NDS_getFinalUserInput();
2578 
2579 	u16	pad	= (0 |
2580 		((input.buttons.A ? 0 : 0x80) >> 7) |
2581 		((input.buttons.B ? 0 : 0x80) >> 6) |
2582 		((input.buttons.T ? 0 : 0x80) >> 5) |
2583 		((input.buttons.S ? 0 : 0x80) >> 4) |
2584 		((input.buttons.R ? 0 : 0x80) >> 3) |
2585 		((input.buttons.L ? 0 : 0x80) >> 2) |
2586 		((input.buttons.U ? 0 : 0x80) >> 1) |
2587 		((input.buttons.D ? 0 : 0x80)     ) |
2588 		((input.buttons.E ? 0 : 0x80) << 1) |
2589 		((input.buttons.W ? 0 : 0x80) << 2)) ;
2590 
2591 	pad = LOCAL_TO_LE_16(pad);
2592 	((u16 *)MMU.ARM9_REG)[0x130>>1] = (u16)pad;
2593 	((u16 *)MMU.ARM7_REG)[0x130>>1] = (u16)pad;
2594 
2595 	u16 k_cnt = ((u16 *)MMU.ARM9_REG)[0x132>>1];
2596 	if ( k_cnt & (1<<14))
2597 	{
2598 		//INFO("ARM9: KeyPad IRQ (pad 0x%04X, cnt 0x%04X (condition %s))\n", pad, k_cnt, k_cnt&(1<<15)?"AND":"OR");
2599 		u16 k_cnt_selected = (k_cnt & 0x3F);
2600 		if (k_cnt&(1<<15))	// AND
2601 		{
2602 			if ((~pad & k_cnt_selected) == k_cnt_selected) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_KEYPAD);
2603 		}
2604 		else				// OR
2605 		{
2606 			if (~pad & k_cnt_selected) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_KEYPAD);
2607 		}
2608 	}
2609 
2610 	k_cnt = ((u16 *)MMU.ARM7_REG)[0x132>>1];
2611 	if ( k_cnt & (1<<14))
2612 	{
2613 		//INFO("ARM7: KeyPad IRQ (pad 0x%04X, cnt 0x%04X (condition %s))\n", pad, k_cnt, k_cnt&(1<<15)?"AND":"OR");
2614 		u16 k_cnt_selected = (k_cnt & 0x3F);
2615 		if (k_cnt&(1<<15))	// AND
2616 		{
2617 			if ((~pad & k_cnt_selected) == k_cnt_selected) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_KEYPAD);
2618 		}
2619 		else				// OR
2620 		{
2621 			if (~pad & k_cnt_selected) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_KEYPAD);
2622 		}
2623 	}
2624 
2625 
2626 	if(input.touch.isTouch)
2627 	{
2628 		u16 adc_x = NDS_getADCTouchPosX(input.touch.touchX);
2629 		u16 adc_y = NDS_getADCTouchPosY(input.touch.touchY);
2630 		nds.adc_touchX = adc_x;
2631 		nds.adc_touchY = adc_y;
2632 		nds.adc_jitterctr = 0;
2633 
2634 		nds.scr_touchX = input.touch.touchX;
2635 		nds.scr_touchY = input.touch.touchY;
2636 		nds.isTouch = 1;
2637 	}
2638 	else
2639 	{
2640 		nds.adc_touchX = 0;
2641 		nds.adc_touchY = 0;
2642 		nds.scr_touchX = 0;
2643 		nds.scr_touchY = 0;
2644 		nds.isTouch = 0;
2645 	}
2646 
2647 	if (input.buttons.F && !countLid)
2648 	{
2649 		LidClosed = (!LidClosed) & 0x01;
2650 		if (!LidClosed)
2651 		{
2652 			NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_ARM7_FOLD);
2653 		}
2654 
2655 		countLid = 30;
2656 	}
2657 	else
2658 	{
2659 		if (countLid > 0)
2660 			countLid--;
2661 	}
2662 
2663 	u16 padExt = ((input.buttons.X ? 0 : 0x80) >> 7) |
2664 		((input.buttons.Y ? 0 : 0x80) >> 6) |
2665 		((input.buttons.G ? 0 : 0x80) >> 4) |
2666 		((LidClosed) << 7) |
2667 		0x0034;
2668 
2669 	padExt = LOCAL_TO_LE_16(padExt);
2670 	padExt |= (((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0070);
2671 
2672 	((u16 *)MMU.ARM7_REG)[0x136>>1] = (u16)padExt;
2673 
2674 	//put into the format we want for the movie system
2675 	//fRLDUTSBAYXWEg
2676 	//we don't really need nds.pad anymore, but removing it would be a pain
2677 
2678  	nds.pad =
2679 		((input.buttons.R ? 1 : 0) << 12)|
2680 		((input.buttons.L ? 1 : 0) << 11)|
2681 		((input.buttons.D ? 1 : 0) << 10)|
2682 		((input.buttons.U ? 1 : 0) << 9)|
2683 		((input.buttons.T ? 1 : 0) << 8)|
2684 		((input.buttons.S ? 1 : 0) << 7)|
2685 		((input.buttons.B ? 1 : 0) << 6)|
2686 		((input.buttons.A ? 1 : 0) << 5)|
2687 		((input.buttons.Y ? 1 : 0) << 4)|
2688 		((input.buttons.X ? 1 : 0) << 3)|
2689 		((input.buttons.W ? 1 : 0) << 2)|
2690 		((input.buttons.E ? 1 : 0) << 1);
2691 }
2692 
2693 
NDS_beginProcessingInput()2694 void NDS_beginProcessingInput()
2695 {
2696 }
2697 
NDS_endProcessingInput()2698 void NDS_endProcessingInput()
2699 {
2700 	// transfer the processed input
2701 	finalUserInput = rawUserInput;
2702 
2703 	// use the final input for a few things right away
2704 	NDS_applyFinalInput();
2705 }
2706 
NDS_suspendProcessingInput(bool suspend)2707 void NDS_suspendProcessingInput(bool suspend)
2708 {
2709 	static int suspendCount = 0;
2710 	if(suspend)
2711 		suspendCount++;
2712 	else if(suspendCount)
2713 		suspendCount--;
2714 }
2715 
NDS_swapScreen()2716 void NDS_swapScreen()
2717 {
2718    if (GPU->GetDisplayMain()->GetEngineID() == GPUEngineID_Main)
2719    {
2720 		GPU->GetDisplayMain()->SetEngineByID(GPUEngineID_Sub);
2721 		GPU->GetDisplayTouch()->SetEngineByID(GPUEngineID_Main);
2722    }
2723    else
2724    {
2725       GPU->GetDisplayMain()->SetEngineByID(GPUEngineID_Main);
2726 		GPU->GetDisplayTouch()->SetEngineByID(GPUEngineID_Sub);
2727    }
2728 }
2729 
2730 #if defined(LOG_ARM9) || defined(LOG_ARM7)
emu_halt()2731 void emu_halt()
2732 {
2733 	//printf("halting emu: ARM9 PC=%08X/%08X, ARM7 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr, NDS_ARM7.R[15], NDS_ARM7.instruct_adr);
2734 	execute = false;
2735 #ifdef LOG_ARM9
2736 	if (fp_dis9)
2737 	{
2738 		char buf[256] = { 0 };
2739 		sprintf(buf, "halting emu: ARM9 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr);
2740 		fwrite(buf, 1, strlen(buf), fp_dis9);
2741 		INFO("ARM9 halted\n");
2742 	}
2743 #endif
2744 
2745 #ifdef LOG_ARM7
2746 	if (fp_dis7)
2747 	{
2748 		char buf[256] = { 0 };
2749 		sprintf(buf, "halting emu: ARM7 PC=%08X/%08X\n", NDS_ARM7.R[15], NDS_ARM7.instruct_adr);
2750 		fwrite(buf, 1, strlen(buf), fp_dis7);
2751 		INFO("ARM7 halted\n");
2752 	}
2753 #endif
2754 }
2755 #endif
2756 
2757 //returns true if exmemcnt specifies satisfactory parameters for the device, which calls this function
ValidateSlot2Access(u32 procnum,u32 demandSRAMSpeed,u32 demand1stROMSpeed,u32 demand2ndROMSpeed,int clockbits)2758 bool ValidateSlot2Access(u32 procnum, u32 demandSRAMSpeed, u32 demand1stROMSpeed, u32 demand2ndROMSpeed, int clockbits)
2759 {
2760 	static const u32 _sramSpeeds[] = {10,8,6,18};
2761 	static const u32 _rom1Speeds[] = {10,8,6,18};
2762 	static const u32 _rom2Speeds[] = {6,4};
2763 	u16 exmemcnt = T1ReadWord(MMU.MMU_MEM[procnum][0x40], 0x204);
2764 	u16 exmemcnt9 = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x204);
2765 	u32 arm7access = (exmemcnt9 & EXMEMCNT_MASK_SLOT2_ARM7);
2766 	u32 sramSpeed = _sramSpeeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_SRAM_TIME)];
2767 	u32 romSpeed1 = _rom1Speeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_ROM_1ST_TIME)>>2];
2768 	u32 romSpeed2 = _rom2Speeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_ROM_2ND_TIME)>>4];
2769 	u32 curclockbits = (exmemcnt & EXMEMCNT_MASK_SLOT2_CLOCKRATE)>>5;
2770 
2771 	if(procnum==ARMCPU_ARM9 && arm7access) return false;
2772 	if(procnum==ARMCPU_ARM7 && !arm7access) return false;
2773 
2774 	//what we're interested in here is whether the rom/ram are too low -> too fast. then accesses won't have enough time to work.
2775 	//i'm not sure if this gives us enough flexibility, but it is good enough for now.
2776 	//should make the arguments to this function bitmasks later if we need better.
2777 	if(sramSpeed < demandSRAMSpeed) return false;
2778 	if(romSpeed1 < demand1stROMSpeed) return false;
2779 	if(romSpeed2 < demand2ndROMSpeed) return false;
2780 
2781 	if(clockbits != -1 && clockbits != (int)curclockbits) return false;
2782 
2783 	return true;
2784 }
2785