| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | // Copyright (C) 2003 Dolphin Project.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, version 2.0.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU General Public License 2.0 for more details.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A copy of the GPL 2.0 should have been included with the program.
 | 
					
						
							|  |  |  | // If not, see http://www.gnu.org/licenses/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Official SVN repository and contact information can be found at
 | 
					
						
							|  |  |  | // http://code.google.com/p/dolphin-emu/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Common.h"
 | 
					
						
							|  |  |  | #include "CPUDetect.h"
 | 
					
						
							| 
									
										
										
										
											2013-03-03 19:18:04 -06:00
										 |  |  | #include "FileUtil.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | // Only Linux platforms have /proc/cpuinfo
 | 
					
						
							|  |  |  | #if !defined(BLACKBERRY) && !defined(IOS) && !defined(__SYMBIAN32__)
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | const char procfile[] = "/proc/cpuinfo"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *GetCPUString() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char marker[] = "Hardware\t: "; | 
					
						
							|  |  |  | 	char *cpu_string = 0; | 
					
						
							|  |  |  | 	// Count the number of processor lines in /proc/cpuinfo
 | 
					
						
							|  |  |  | 	char buf[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 19:18:04 -06:00
										 |  |  | 	File::IOFile file(procfile, "r"); | 
					
						
							|  |  |  | 	auto const fp = file.GetHandle(); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	if (!fp) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	while (fgets(buf, sizeof(buf), fp)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (strncmp(buf, marker, sizeof(marker) - 1)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		cpu_string = buf + sizeof(marker) - 1; | 
					
						
							|  |  |  | 		cpu_string = strndup(cpu_string, strlen(cpu_string) - 1); // Strip the newline
 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	return cpu_string; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-07-16 01:22:06 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | unsigned char GetCPUImplementer() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char marker[] = "CPU implementer\t: "; | 
					
						
							|  |  |  | 	char *implementer_string = 0; | 
					
						
							|  |  |  | 	unsigned char implementer = 0; | 
					
						
							|  |  |  | 	char buf[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	File::IOFile file(procfile, "r"); | 
					
						
							|  |  |  | 	auto const fp = file.GetHandle(); | 
					
						
							|  |  |  | 	if (!fp) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (fgets(buf, sizeof(buf), fp)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (strncmp(buf, marker, sizeof(marker) - 1)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		implementer_string = buf + sizeof(marker) - 1; | 
					
						
							|  |  |  | 		implementer_string = strndup(implementer_string, strlen(implementer_string) - 1); // Strip the newline
 | 
					
						
							|  |  |  | 		sscanf(implementer_string, "0x%02hhx", &implementer); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-08-06 18:17:54 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	free(implementer_string); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 01:22:06 -05:00
										 |  |  | 	return implementer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned short GetCPUPart() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char marker[] = "CPU part\t: "; | 
					
						
							|  |  |  | 	char *part_string = 0; | 
					
						
							|  |  |  | 	unsigned short part = 0; | 
					
						
							|  |  |  | 	char buf[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	File::IOFile file(procfile, "r"); | 
					
						
							|  |  |  | 	auto const fp = file.GetHandle(); | 
					
						
							|  |  |  | 	if (!fp) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (fgets(buf, sizeof(buf), fp)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (strncmp(buf, marker, sizeof(marker) - 1)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		part_string = buf + sizeof(marker) - 1; | 
					
						
							|  |  |  | 		part_string = strndup(part_string, strlen(part_string) - 1); // Strip the newline
 | 
					
						
							|  |  |  | 		sscanf(part_string, "0x%03hx", &part); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-08-06 18:17:54 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	free(part_string); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 01:22:06 -05:00
										 |  |  | 	return part; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | bool CheckCPUFeature(const char *feature) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char marker[] = "Features\t: "; | 
					
						
							|  |  |  | 	char buf[1024]; | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 19:18:04 -06:00
										 |  |  | 	File::IOFile file(procfile, "r"); | 
					
						
							|  |  |  | 	auto const fp = file.GetHandle(); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	if (!fp) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	while (fgets(buf, sizeof(buf), fp)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (strncmp(buf, marker, sizeof(marker) - 1)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		char *featurestring = buf + sizeof(marker) - 1; | 
					
						
							|  |  |  | 		char *token = strtok(featurestring, " "); | 
					
						
							|  |  |  | 		while (token != NULL) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (strstr(token, feature)) | 
					
						
							|  |  |  | 				return true;  | 
					
						
							|  |  |  | 			token = strtok(NULL, " "); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | int GetCoreCount() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | #ifdef __SYMBIAN32__
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | #elif defined(BLACKBERRY) || defined(IOS)
 | 
					
						
							|  |  |  | 	return 2; | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	const char marker[] = "processor\t: "; | 
					
						
							|  |  |  | 	int cores = 0; | 
					
						
							|  |  |  | 	char buf[1024]; | 
					
						
							| 
									
										
										
										
											2013-03-19 21:51:12 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 19:18:04 -06:00
										 |  |  | 	File::IOFile file(procfile, "r"); | 
					
						
							|  |  |  | 	auto const fp = file.GetHandle(); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	if (!fp) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	while (fgets(buf, sizeof(buf), fp)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (strncmp(buf, marker, sizeof(marker) - 1)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		++cores; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	return cores; | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CPUInfo cpu_info; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CPUInfo::CPUInfo() { | 
					
						
							|  |  |  | 	Detect(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Detects the various cpu features
 | 
					
						
							|  |  |  | void CPUInfo::Detect() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// Set some defaults here
 | 
					
						
							|  |  |  | 	// When ARMv8 cpus come out, these need to be updated.
 | 
					
						
							|  |  |  | 	HTT = false; | 
					
						
							|  |  |  | 	OS64bit = false; | 
					
						
							|  |  |  | 	CPU64bit = false; | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 	Mode64bit = false;				  | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	vendor = VENDOR_ARM; | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	// Get the information about the CPU 
 | 
					
						
							| 
									
										
										
										
											2013-03-19 21:51:12 -04:00
										 |  |  | 	num_cores = GetCoreCount(); | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | #if defined(__SYMBIAN32__) || defined(BLACKBERRY) || defined(IOS)
 | 
					
						
							|  |  |  | 	bool isVFP3 = false; | 
					
						
							|  |  |  | 	bool isVFP4 = false; | 
					
						
							|  |  |  | #ifdef IOS
 | 
					
						
							|  |  |  | 	isVFP3 = true; | 
					
						
							|  |  |  |     // Check for swift arch (VFP4`)
 | 
					
						
							|  |  |  |     #ifdef __ARM_ARCH_7S__
 | 
					
						
							|  |  |  |         isVFP4 = true; | 
					
						
							|  |  |  |     #endif // #ifdef __ARM_ARCH_7S__
 | 
					
						
							|  |  |  | #elif defined(BLACKBERRY)
 | 
					
						
							|  |  |  | 	isVFP3 = true; | 
					
						
							|  |  |  | 	const char cpuInfoPath[] = "/pps/services/hw_info/inventory"; | 
					
						
							|  |  |  | 	const char marker[] = "Processor_Name::"; | 
					
						
							|  |  |  | 	const char qcCPU[] = "MSM"; | 
					
						
							|  |  |  | 	char buf[1024]; | 
					
						
							|  |  |  | 	FILE* fp; | 
					
						
							|  |  |  | 	if (fp = fopen(cpuInfoPath, "r")) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		while (fgets(buf, sizeof(buf), fp)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (strncmp(buf, marker, sizeof(marker) - 1)) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			if (strncmp(buf + sizeof(marker) - 1, qcCPU, sizeof(qcCPU) - 1) == 0) | 
					
						
							|  |  |  | 				isVFP4 = true; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fclose(fp); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	// Hardcode this for now
 | 
					
						
							|  |  |  | 	bSwp = true; | 
					
						
							|  |  |  | 	bHalf = true; | 
					
						
							|  |  |  | 	bThumb = false; | 
					
						
							|  |  |  | 	bFastMult = true; | 
					
						
							|  |  |  | 	bVFP = true; | 
					
						
							|  |  |  | 	bEDSP = true; | 
					
						
							|  |  |  | 	bThumbEE = isVFP3; | 
					
						
							|  |  |  | 	bNEON = isVFP3; | 
					
						
							|  |  |  | 	bVFPv3 = isVFP3; | 
					
						
							|  |  |  | 	bTLS = true; | 
					
						
							|  |  |  | 	bVFPv4 = isVFP4; | 
					
						
							|  |  |  | 	bIDIVa = isVFP4; | 
					
						
							|  |  |  | 	bIDIVt = isVFP4; | 
					
						
							|  |  |  | 	bFP = false; | 
					
						
							|  |  |  | 	bASIMD = false; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	strncpy(cpu_string, GetCPUString(), sizeof(cpu_string)); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	bSwp = CheckCPUFeature("swp"); | 
					
						
							|  |  |  | 	bHalf = CheckCPUFeature("half"); | 
					
						
							|  |  |  | 	bThumb = CheckCPUFeature("thumb"); | 
					
						
							|  |  |  | 	bFastMult = CheckCPUFeature("fastmult"); | 
					
						
							|  |  |  | 	bVFP = CheckCPUFeature("vfp"); | 
					
						
							|  |  |  | 	bEDSP = CheckCPUFeature("edsp"); | 
					
						
							|  |  |  | 	bThumbEE = CheckCPUFeature("thumbee"); | 
					
						
							|  |  |  | 	bNEON = CheckCPUFeature("neon"); | 
					
						
							|  |  |  | 	bVFPv3 = CheckCPUFeature("vfpv3"); | 
					
						
							|  |  |  | 	bTLS = CheckCPUFeature("tls"); | 
					
						
							|  |  |  | 	bVFPv4 = CheckCPUFeature("vfpv4"); | 
					
						
							|  |  |  | 	bIDIVa = CheckCPUFeature("idiva"); | 
					
						
							|  |  |  | 	bIDIVt = CheckCPUFeature("idivt"); | 
					
						
							| 
									
										
										
										
											2013-07-16 01:22:06 -05:00
										 |  |  | 	// Qualcomm Krait supports IDIVA but it doesn't report it. Check for krait.
 | 
					
						
							|  |  |  | 	if (GetCPUImplementer() == 0x51 && GetCPUPart() == 0x6F) // Krait(300) is 0x6F, Scorpion is 0x4D
 | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | 		bIDIVa = bIDIVt = true; | 
					
						
							|  |  |  | 	// These two require ARMv8 or higher
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	bFP = CheckCPUFeature("fp"); | 
					
						
							|  |  |  | 	bASIMD = CheckCPUFeature("asimd"); | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | // On android, we build a separate library for ARMv7 so this is fine.
 | 
					
						
							|  |  |  | // TODO: Check for ARMv7 on other platforms.
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #if defined(__ARM_ARCH_7A__)
 | 
					
						
							|  |  |  | 	bArmV7 = true; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	bArmV7 = false; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Turn the cpu info into a string we can show
 | 
					
						
							|  |  |  | std::string CPUInfo::Summarize() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	std::string sum; | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | #if defined(BLACKBERRY) || defined(IOS) || defined(__SYMBIAN32__)
 | 
					
						
							|  |  |  | 	sum = StringFromFormat("%i cores", num_cores); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	if (num_cores == 1) | 
					
						
							|  |  |  | 		sum = StringFromFormat("%s, %i core", cpu_string, num_cores); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		sum = StringFromFormat("%s, %i cores", cpu_string, num_cores); | 
					
						
							| 
									
										
										
										
											2013-08-02 23:18:44 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	if (bSwp) sum += ", SWP"; | 
					
						
							|  |  |  | 	if (bHalf) sum += ", Half"; | 
					
						
							|  |  |  | 	if (bThumb) sum += ", Thumb"; | 
					
						
							|  |  |  | 	if (bFastMult) sum += ", FastMult"; | 
					
						
							|  |  |  | 	if (bVFP) sum += ", VFP"; | 
					
						
							|  |  |  | 	if (bEDSP) sum += ", EDSP"; | 
					
						
							|  |  |  | 	if (bThumbEE) sum += ", ThumbEE"; | 
					
						
							|  |  |  | 	if (bNEON) sum += ", NEON"; | 
					
						
							|  |  |  | 	if (bVFPv3) sum += ", VFPv3"; | 
					
						
							|  |  |  | 	if (bTLS) sum += ", TLS"; | 
					
						
							|  |  |  | 	if (bVFPv4) sum += ", VFPv4"; | 
					
						
							| 
									
										
										
										
											2013-03-14 08:48:01 -05:00
										 |  |  | 	if (bIDIVa) sum += ", IDIVa"; | 
					
						
							|  |  |  | 	if (bIDIVt) sum += ", IDIVt"; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return sum; | 
					
						
							|  |  |  | } |