psphawk
This commit is contained in:
parent
b6ac0ff88a
commit
39f82cbca9
|
@ -366,6 +366,8 @@
|
|||
<Compile Include="Consoles\Sega\SMS\VDP.ModeTMS.cs" />
|
||||
<Compile Include="Consoles\Sega\SMS\VDP.Mode4.cs" />
|
||||
<Compile Include="Consoles\Sega\SMS\VDP.Tables.cs" />
|
||||
<Compile Include="Consoles\Sony\PSP\PPSSPPDll.cs" />
|
||||
<Compile Include="Consoles\Sony\PSP\PSP.cs" />
|
||||
<Compile Include="CPUs\68000\Diassembler.cs" />
|
||||
<Compile Include="CPUs\68000\Instructions\BitArithemetic.cs" />
|
||||
<Compile Include="CPUs\68000\Instructions\DataMovement.cs" />
|
||||
|
|
|
@ -2117,15 +2117,24 @@ namespace BizHawk.MultiClient
|
|||
{
|
||||
case "SAT":
|
||||
{
|
||||
string biosPath = PathManager.StandardFirmwareName(Global.Config.FilenameSaturnBios);
|
||||
if (!File.Exists(biosPath))
|
||||
// hax ahoy: use this to instead load the PSP when you "load" a saturn rom.
|
||||
if (false)
|
||||
{
|
||||
MessageBox.Show("Saturn BIOS not found. Please check firmware configurations.");
|
||||
return false;
|
||||
var psp = new Emulation.Consoles.Sony.PSP.PSP(nextComm);
|
||||
nextEmulator = psp;
|
||||
}
|
||||
else
|
||||
{
|
||||
string biosPath = PathManager.StandardFirmwareName(Global.Config.FilenameSaturnBios);
|
||||
if (!File.Exists(biosPath))
|
||||
{
|
||||
MessageBox.Show("Saturn BIOS not found. Please check firmware configurations.");
|
||||
return false;
|
||||
}
|
||||
var saturn = new Emulation.Consoles.Sega.Saturn.Yabause(nextComm, disc, File.ReadAllBytes(biosPath), Global.Config.SaturnUseGL);
|
||||
nextEmulator = saturn;
|
||||
SaturnSetPrefs(saturn);
|
||||
}
|
||||
var saturn = new Emulation.Consoles.Sega.Saturn.Yabause(nextComm, disc, File.ReadAllBytes(biosPath), Global.Config.SaturnUseGL);
|
||||
nextEmulator = saturn;
|
||||
SaturnSetPrefs(saturn);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -675,6 +675,10 @@ namespace BizHawk.MultiClient
|
|||
{
|
||||
return GetSaturnControllersAsMnemonic();
|
||||
}
|
||||
else if (ControlType == "PSP Controller")
|
||||
{
|
||||
return "|.|"; // TODO
|
||||
}
|
||||
|
||||
StringBuilder input = new StringBuilder("|");
|
||||
|
||||
|
@ -1210,6 +1214,11 @@ namespace BizHawk.MultiClient
|
|||
SetSaturnControllersAsMnemonic(mnemonic);
|
||||
return;
|
||||
}
|
||||
else if (ControlType == "PSP Controller")
|
||||
{
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
|
||||
MnemonicChecker c = new MnemonicChecker(mnemonic);
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,607 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="96px"
|
||||
height="96px" viewBox="0 0 96 96" enable-background="new 0 0 96 96" xml:space="preserve">
|
||||
<g id="DO_NOT_EDIT_-_BOUNDING_BOX">
|
||||
<rect id="BOUNDING_BOX" fill="none" width="96" height="96"/>
|
||||
</g>
|
||||
<g id="DO_NOT_EDIT_-_SHADOW">
|
||||
<path id="SHADOW" opacity="0.4" d="M88.023,49c0,29.633-10.364,40-40,40c-29.635,0-40-10.367-40-40c0-29.634,10.366-40,40-40
|
||||
C77.659,9,88.023,19.365,88.023,49z"/>
|
||||
</g>
|
||||
<g id="GRAY_BACKGROUNDS">
|
||||
<linearGradient id="GRAY_5_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.1505" style="stop-color:#F7F7F8"/>
|
||||
<stop offset="0.6237" style="stop-color:#D9D9DB"/>
|
||||
<stop offset="0.8817" style="stop-color:#CDCDD0"/>
|
||||
</linearGradient>
|
||||
<path id="GRAY_5" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GRAY_5_1_)" d="M8,47.989c0,29.633,10.365,40,40,40
|
||||
c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_GRA5_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.3366" style="stop-color:#E1E1E3"/>
|
||||
<stop offset="0.9874" style="stop-color:#96969A"/>
|
||||
<stop offset="1" style="stop-color:#949499"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GRA5" opacity="0.25" fill="url(#HIGHLIGHT_GRA5_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
<g id="GRAY4" display="none">
|
||||
<linearGradient id="GRAY_4_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#E0E0E0"/>
|
||||
<stop offset="0.3262" style="stop-color:#D6D6D6"/>
|
||||
<stop offset="0.8148" style="stop-color:#BCBCBC"/>
|
||||
<stop offset="1" style="stop-color:#B0B0B0"/>
|
||||
</linearGradient>
|
||||
<path id="GRAY_4" display="inline" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GRAY_4_1_)" d="M8,47.989
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"
|
||||
/>
|
||||
<linearGradient id="HIGHLIGHT_GRA4_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#E8E8E8"/>
|
||||
<stop offset="0.2978" style="stop-color:#DEDEDE"/>
|
||||
<stop offset="0.7385" style="stop-color:#C4C4C4"/>
|
||||
<stop offset="1" style="stop-color:#B1B1B1"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GRA4_1_" display="inline" fill="url(#HIGHLIGHT_GRA4_2_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="GRAY3" display="none">
|
||||
<linearGradient id="GRAY_3_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#E9E9E9"/>
|
||||
<stop offset="0.3218" style="stop-color:#DFDFDF"/>
|
||||
<stop offset="0.8028" style="stop-color:#C5C5C5"/>
|
||||
<stop offset="1" style="stop-color:#B8B8B8"/>
|
||||
</linearGradient>
|
||||
<path id="GRAY_3" display="inline" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GRAY_3_1_)" d="M8,47.989
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"
|
||||
/>
|
||||
<linearGradient id="HIGHLIGHT_GRA3_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#EFEFEF"/>
|
||||
<stop offset="0.3133" style="stop-color:#E5E5E5"/>
|
||||
<stop offset="0.7799" style="stop-color:#CBCBCB"/>
|
||||
<stop offset="1" style="stop-color:#BCBCBC"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GRA3_1_" display="inline" fill="url(#HIGHLIGHT_GRA3_2_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="GRAY2" display="none">
|
||||
<linearGradient id="GRAY_2_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#EEEEEE"/>
|
||||
<stop offset="0.3262" style="stop-color:#E4E4E4"/>
|
||||
<stop offset="0.8148" style="stop-color:#CACACA"/>
|
||||
<stop offset="1" style="stop-color:#BEBEBE"/>
|
||||
</linearGradient>
|
||||
<path id="GRAY_2" display="inline" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GRAY_2_1_)" d="M8,47.989
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"
|
||||
/>
|
||||
<linearGradient id="HIGHLIGHT_GRA2_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#F2F2F2"/>
|
||||
<stop offset="0.3133" style="stop-color:#E8E8E8"/>
|
||||
<stop offset="0.7799" style="stop-color:#CECECE"/>
|
||||
<stop offset="1" style="stop-color:#BFBFBF"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GRA2" display="inline" fill="url(#HIGHLIGHT_GRA2_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="GRAY1" display="none">
|
||||
<linearGradient id="GRAY_1_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#F9F9F9"/>
|
||||
<stop offset="0.2102" style="stop-color:#EFEFEF"/>
|
||||
<stop offset="0.5042" style="stop-color:#D6D6D5"/>
|
||||
<stop offset="0.8303" style="stop-color:#B2B2B0"/>
|
||||
<stop offset="1" style="stop-color:#ABABA8"/>
|
||||
</linearGradient>
|
||||
<path id="GRAY_1" display="inline" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GRAY_1_1_)" d="M8,47.989
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"
|
||||
/>
|
||||
<linearGradient id="HIGHLIGHT_GRA1_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#FCFCFC"/>
|
||||
<stop offset="0.2262" style="stop-color:#F3F3F2"/>
|
||||
<stop offset="0.5471" style="stop-color:#DAD9D8"/>
|
||||
<stop offset="0.9576" style="stop-color:#B2B0AD"/>
|
||||
<stop offset="1" style="stop-color:#ADABA8"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GRA1" display="inline" fill="url(#HIGHLIGHT_GRA1_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="ORANGE_BACKGROUNDS" display="none">
|
||||
<g id="ORANGE_5" display="inline">
|
||||
<linearGradient id="RED_x2F_ORANGE_5_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0" style="stop-color:#FFDB62"/>
|
||||
<stop offset="0.1393" style="stop-color:#FAD15C"/>
|
||||
<stop offset="0.3741" style="stop-color:#EDB74D"/>
|
||||
<stop offset="0.4848" style="stop-color:#E6A844"/>
|
||||
<stop offset="1" style="stop-color:#C96B25"/>
|
||||
</linearGradient>
|
||||
<path id="RED_x2F_ORANGE_5_1_" fill="url(#RED_x2F_ORANGE_5_2_)" d="M8,47.988c0,29.634,10.365,40.001,40,40.001
|
||||
c29.637,0,40-10.367,40-40.001c0-28.984-9.926-39.529-38.091-39.978h-3.817C17.928,8.459,8,19.004,8,47.988z"/>
|
||||
<linearGradient id="HIGHLIGHTS_RO5_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.0958" style="stop-color:#FDF8F5"/>
|
||||
<stop offset="0.2579" style="stop-color:#F6E6DB"/>
|
||||
<stop offset="0.4666" style="stop-color:#EBC9AF"/>
|
||||
<stop offset="0.7136" style="stop-color:#DCA073"/>
|
||||
<stop offset="0.9904" style="stop-color:#CA6D28"/>
|
||||
<stop offset="1" style="stop-color:#C96B25"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHTS_RO5" opacity="0.25" fill="url(#HIGHLIGHTS_RO5_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="ORANGE_4">
|
||||
<linearGradient id="RED_x2F_ORANGE_4_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#FBBF60"/>
|
||||
<stop offset="0.2109" style="stop-color:#F8B556"/>
|
||||
<stop offset="0.503" style="stop-color:#F19B3D"/>
|
||||
<stop offset="1" style="stop-color:#C76121"/>
|
||||
</linearGradient>
|
||||
<path id="RED_x2F_ORANGE_4_2_" display="inline" fill="url(#RED_x2F_ORANGE_4_1_)" d="M8,47.988c0,29.634,10.365,40.001,40,40.001
|
||||
c29.637,0,40-10.367,40-40.001c0-28.984-9.926-39.529-38.091-39.978h-3.817C17.928,8.459,8,19.004,8,47.988z"/>
|
||||
<linearGradient id="HIGHLIGHTS_RO4_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.1274" style="stop-color:#FDF8F5"/>
|
||||
<stop offset="0.2815" style="stop-color:#F6E5DB"/>
|
||||
<stop offset="0.4799" style="stop-color:#EBC6AF"/>
|
||||
<stop offset="0.7147" style="stop-color:#DC9C73"/>
|
||||
<stop offset="0.9778" style="stop-color:#C96628"/>
|
||||
<stop offset="1" style="stop-color:#C76121"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHTS_RO4_1_" display="inline" opacity="0.25" fill="url(#HIGHLIGHTS_RO4_2_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="ORANGE_3">
|
||||
<linearGradient id="RED_x2F_ORANGE_3_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#F6B85E"/>
|
||||
<stop offset="0.2008" style="stop-color:#F4AE5A"/>
|
||||
<stop offset="0.478" style="stop-color:#EE9451"/>
|
||||
<stop offset="0.5394" style="stop-color:#EC8D4E"/>
|
||||
<stop offset="0.8228" style="stop-color:#D46A3B"/>
|
||||
<stop offset="1" style="stop-color:#C95932"/>
|
||||
</linearGradient>
|
||||
<path id="RED_x2F_ORANGE_3_1_" display="inline" fill="url(#RED_x2F_ORANGE_3_2_)" d="M8,47.988c0,29.634,10.365,40.001,40,40.001
|
||||
c29.637,0,40-10.367,40-40.001c0-28.984-9.926-39.529-38.091-39.978h-3.817C17.928,8.459,8,19.004,8,47.988z"/>
|
||||
<linearGradient id="HIGHLIGHTS_RO3_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.133" style="stop-color:#FCF7F5"/>
|
||||
<stop offset="0.2967" style="stop-color:#F5E2DB"/>
|
||||
<stop offset="0.5073" style="stop-color:#EABFAF"/>
|
||||
<stop offset="0.7537" style="stop-color:#DA8F74"/>
|
||||
<stop offset="1" style="stop-color:#C95932"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHTS_RO3_1_" display="inline" opacity="0.25" fill="url(#HIGHLIGHTS_RO3_2_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="ORANGE_2">
|
||||
<linearGradient id="RED_x2F_ORANGE_2_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#FAA824"/>
|
||||
<stop offset="0.3742" style="stop-color:#EA8A20"/>
|
||||
<stop offset="1" style="stop-color:#C74A17"/>
|
||||
</linearGradient>
|
||||
<path id="RED_x2F_ORANGE_2_2_" display="inline" fill="url(#RED_x2F_ORANGE_2_1_)" d="M8,47.988c0,29.634,10.365,40.001,40,40.001
|
||||
c29.637,0,40-10.367,40-40.001c0-28.984-9.926-39.529-38.091-39.978h-3.817C17.928,8.459,8,19.004,8,47.988z"/>
|
||||
<linearGradient id="HIGHLIGHTS_RO2_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.185" style="stop-color:#F8E8E1"/>
|
||||
<stop offset="0.5097" style="stop-color:#E5AC95"/>
|
||||
<stop offset="0.9833" style="stop-color:#C84D1B"/>
|
||||
<stop offset="1" style="stop-color:#C74A17"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHTS_RO2_2_" display="inline" opacity="0.25" fill="url(#HIGHLIGHTS_RO2_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="ORANGE_1">
|
||||
<linearGradient id="RED_x2F_ORANGE_1_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#FF8A36"/>
|
||||
<stop offset="0.3489" style="stop-color:#EF7130"/>
|
||||
<stop offset="1" style="stop-color:#C73321"/>
|
||||
</linearGradient>
|
||||
<path id="RED_x2F_ORANGE_1_1_" display="inline" fill="url(#RED_x2F_ORANGE_1_2_)" d="M8,47.988c0,29.634,10.365,40.001,40,40.001
|
||||
c29.637,0,40-10.367,40-40.001c0-28.984-9.926-39.529-38.091-39.978h-3.817C17.928,8.459,8,19.004,8,47.988z"/>
|
||||
<linearGradient id="HIGHLIGHTS_RO1_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.1274" style="stop-color:#FCF7F5"/>
|
||||
<stop offset="0.2815" style="stop-color:#F5E0DB"/>
|
||||
<stop offset="0.4799" style="stop-color:#EABBAF"/>
|
||||
<stop offset="0.7147" style="stop-color:#DA8873"/>
|
||||
<stop offset="0.9778" style="stop-color:#C64828"/>
|
||||
<stop offset="1" style="stop-color:#C44221"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHTS_RO1_1_" display="inline" opacity="0.25" fill="url(#HIGHLIGHTS_RO1_2_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="GREEN_BACKGROUNDS" display="none">
|
||||
<g id="GREEN4" display="inline">
|
||||
<linearGradient id="GREEN_4_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#6BAB40"/>
|
||||
<stop offset="0.6061" style="stop-color:#537734"/>
|
||||
<stop offset="1" style="stop-color:#4F5C26"/>
|
||||
</linearGradient>
|
||||
<path id="GREEN_4_3_" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GREEN_4_1_)" d="M8,47.989c0,29.633,10.365,40,40,40
|
||||
c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_GR4_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.8255" style="stop-color:#6F7A4E"/>
|
||||
<stop offset="1" style="stop-color:#4F5C26"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GR4" opacity="0.25" fill="url(#HIGHLIGHT_GR4_1_)" d="M48,8C18.365,8,8,18.365,8,48c0,29.633,10.365,40,40,40
|
||||
c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48S18.842,8.977,48,8.977
|
||||
S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="GREEN3">
|
||||
<linearGradient id="GREEN_3_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#70B83B"/>
|
||||
<stop offset="0.2066" style="stop-color:#6AAE37"/>
|
||||
<stop offset="0.4945" style="stop-color:#5B942B"/>
|
||||
<stop offset="0.8626" style="stop-color:#426917"/>
|
||||
<stop offset="1" style="stop-color:#38570F"/>
|
||||
</linearGradient>
|
||||
<path id="GREEN_3_2_" display="inline" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GREEN_3_1_)" d="M8,47.989
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"
|
||||
/>
|
||||
<linearGradient id="HIGHLIGHT_GR3_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.1222" style="stop-color:#F7F8F5"/>
|
||||
<stop offset="0.2675" style="stop-color:#E1E5DB"/>
|
||||
<stop offset="0.4545" style="stop-color:#BDC7AF"/>
|
||||
<stop offset="0.6759" style="stop-color:#8B9D73"/>
|
||||
<stop offset="0.9238" style="stop-color:#4D6828"/>
|
||||
<stop offset="1" style="stop-color:#38570F"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GR3" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_GR3_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="GREEN2">
|
||||
<linearGradient id="GREEN_2_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#75B561"/>
|
||||
<stop offset="0.223" style="stop-color:#6EAB5E"/>
|
||||
<stop offset="0.5376" style="stop-color:#5B9157"/>
|
||||
<stop offset="0.6667" style="stop-color:#528454"/>
|
||||
<stop offset="1" style="stop-color:#4B6145"/>
|
||||
</linearGradient>
|
||||
<path id="GREEN_2_2_" display="inline" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GREEN_2_1_)" d="M8,47.989
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"
|
||||
/>
|
||||
<linearGradient id="HIGHLIGHT_GR2_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.1404" style="stop-color:#F5F7F5"/>
|
||||
<stop offset="0.3165" style="stop-color:#DCE0DB"/>
|
||||
<stop offset="0.543" style="stop-color:#B2BBAF"/>
|
||||
<stop offset="0.8084" style="stop-color:#798974"/>
|
||||
<stop offset="1" style="stop-color:#4B6145"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GR2" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_GR2_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="GREEN1">
|
||||
<linearGradient id="GREEN_1_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#9CD061"/>
|
||||
<stop offset="0.219" style="stop-color:#94C957"/>
|
||||
<stop offset="0.5269" style="stop-color:#7DB63D"/>
|
||||
<stop offset="0.6909" style="stop-color:#6FAA2C"/>
|
||||
<stop offset="1" style="stop-color:#4A8021"/>
|
||||
</linearGradient>
|
||||
<path id="GREEN_1_2_" display="inline" fill-rule="evenodd" clip-rule="evenodd" fill="url(#GREEN_1_1_)" d="M8,47.989
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"
|
||||
/>
|
||||
<linearGradient id="HIGHLIGHT_GR1_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8" x2="47.9995" y2="88.0005">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.1274" style="stop-color:#F7F9F5"/>
|
||||
<stop offset="0.2815" style="stop-color:#E1EADB"/>
|
||||
<stop offset="0.4799" style="stop-color:#BED1AF"/>
|
||||
<stop offset="0.7147" style="stop-color:#8DAF73"/>
|
||||
<stop offset="0.9778" style="stop-color:#4F8428"/>
|
||||
<stop offset="1" style="stop-color:#4A8021"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_GR1" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_GR1_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="BLUE_BACKGROUNDS" display="none">
|
||||
<g id="BLUE_4_2_" display="inline">
|
||||
<linearGradient id="BLUE_4_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#4791D9"/>
|
||||
<stop offset="0.2496" style="stop-color:#4288CF"/>
|
||||
<stop offset="0.6102" style="stop-color:#366EB5"/>
|
||||
<stop offset="1" style="stop-color:#264C91"/>
|
||||
</linearGradient>
|
||||
<path id="BLUE_4_1_" fill="url(#BLUE_4_3_)" d="M8,47.989c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40
|
||||
c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_BLU4_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.129" style="stop-color:#F5F7FA"/>
|
||||
<stop offset="0.2858" style="stop-color:#DBE1ED"/>
|
||||
<stop offset="0.4876" style="stop-color:#AFBDD7"/>
|
||||
<stop offset="0.7265" style="stop-color:#738CB8"/>
|
||||
<stop offset="0.9942" style="stop-color:#284D92"/>
|
||||
<stop offset="1" style="stop-color:#264C91"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_BLU4" opacity="0.25" fill="url(#HIGHLIGHT_BLU4_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="BLUE_3_2_">
|
||||
<linearGradient id="BLUE_3_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#66A2D3"/>
|
||||
<stop offset="0.2002" style="stop-color:#5C9BCE"/>
|
||||
<stop offset="0.4773" style="stop-color:#4289C1"/>
|
||||
<stop offset="0.8316" style="stop-color:#176CAB"/>
|
||||
<stop offset="1" style="stop-color:#005DA0"/>
|
||||
</linearGradient>
|
||||
<path id="BLUE_3_1_" display="inline" fill="url(#BLUE_3_3_)" d="M8,47.989c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40
|
||||
c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_BLU3_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.1184" style="stop-color:#F5F9FC"/>
|
||||
<stop offset="0.2572" style="stop-color:#DBE9F5"/>
|
||||
<stop offset="0.4359" style="stop-color:#AFCFEA"/>
|
||||
<stop offset="0.6475" style="stop-color:#73ACDA"/>
|
||||
<stop offset="0.8842" style="stop-color:#287FC6"/>
|
||||
<stop offset="1" style="stop-color:#0067BC"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_BLU3" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_BLU3_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="BLUE_2_2_">
|
||||
<linearGradient id="BLUE_2_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#63B3E0"/>
|
||||
<stop offset="0.204" style="stop-color:#59ACDA"/>
|
||||
<stop offset="0.4875" style="stop-color:#3F99C9"/>
|
||||
<stop offset="0.8499" style="stop-color:#147BAE"/>
|
||||
<stop offset="1" style="stop-color:#006DA2"/>
|
||||
</linearGradient>
|
||||
<path id="BLUE_2_1_" display="inline" fill="url(#BLUE_2_3_)" d="M8,47.989c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40
|
||||
c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_BLU2_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.1233" style="stop-color:#F5F9FB"/>
|
||||
<stop offset="0.2704" style="stop-color:#DBE7F0"/>
|
||||
<stop offset="0.4598" style="stop-color:#AFCBDD"/>
|
||||
<stop offset="0.6841" style="stop-color:#73A4C4"/>
|
||||
<stop offset="0.9352" style="stop-color:#2873A4"/>
|
||||
<stop offset="1" style="stop-color:#13659B"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_BLU2" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_BLU2_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="BLUE_1_1_">
|
||||
<linearGradient id="BLUE_1_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#6BCFDB"/>
|
||||
<stop offset="0.1944" style="stop-color:#61C7D4"/>
|
||||
<stop offset="0.4617" style="stop-color:#47B0C3"/>
|
||||
<stop offset="0.8033" style="stop-color:#1C8CA6"/>
|
||||
<stop offset="1" style="stop-color:#007594"/>
|
||||
</linearGradient>
|
||||
<path id="BLUE_1_2_" display="inline" fill="url(#BLUE_1_3_)" d="M8,47.989c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40
|
||||
c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_BLU1_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2559" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFDF2"/>
|
||||
<stop offset="0.1064" style="stop-color:#F5F8F0"/>
|
||||
<stop offset="0.2248" style="stop-color:#DBEBE9"/>
|
||||
<stop offset="0.3771" style="stop-color:#AFD5DF"/>
|
||||
<stop offset="0.5394" style="stop-color:#7ABAD2"/>
|
||||
<stop offset="1" style="stop-color:#00879A"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_BLU1" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_BLU1_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
S18.842,8.977,48,8.977S87,18.824,87,48S77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="VIOLET_x2F_PINK_BACKGROUNDS" display="none">
|
||||
<g id="PINK_2_2_" display="inline">
|
||||
<linearGradient id="PINK_2_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#FF61C7"/>
|
||||
<stop offset="0.1942" style="stop-color:#F759C1"/>
|
||||
<stop offset="0.4381" style="stop-color:#E145B1"/>
|
||||
<stop offset="0.7357" style="stop-color:#BE2396"/>
|
||||
<stop offset="1" style="stop-color:#99007A"/>
|
||||
</linearGradient>
|
||||
<path id="PINK_2_1_" fill="url(#PINK_2_3_)" d="M8,47.988c0,29.634,10.365,40.001,40,40.001c29.637,0,40-10.367,40-40.001
|
||||
c0-28.984-9.926-39.529-38.091-39.978h-3.817C17.928,8.459,8,19.004,8,47.988z"/>
|
||||
<linearGradient id="HIGHLIGHT_PI2_2_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2554" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.119" style="stop-color:#FCF7FB"/>
|
||||
<stop offset="0.2468" style="stop-color:#F3E1F0"/>
|
||||
<stop offset="0.4038" style="stop-color:#E5BEDD"/>
|
||||
<stop offset="0.5839" style="stop-color:#D18CC3"/>
|
||||
<stop offset="0.7837" style="stop-color:#B84DA2"/>
|
||||
<stop offset="0.9971" style="stop-color:#99017B"/>
|
||||
<stop offset="1" style="stop-color:#99007A"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_PI2_1_" opacity="0.25" fill="url(#HIGHLIGHT_PI2_2_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.632,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
C9,18.824,18.842,8.976,48,8.976S87,18.824,87,48C87,77.176,77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="PINK_1_2_">
|
||||
<linearGradient id="PINK_1_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="87.9897">
|
||||
<stop offset="0.0364" style="stop-color:#E64DD4"/>
|
||||
<stop offset="0.2159" style="stop-color:#DE46CE"/>
|
||||
<stop offset="0.4932" style="stop-color:#C832BC"/>
|
||||
<stop offset="0.8319" style="stop-color:#A5129F"/>
|
||||
<stop offset="1" style="stop-color:#91008F"/>
|
||||
</linearGradient>
|
||||
<path id="PINK_1_1_" display="inline" fill="url(#PINK_1_3_)" d="M8,47.989c0,29.633,10.365,40,40,40c29.637,0,40-10.367,40-40
|
||||
c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_PI2_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2554" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.119" style="stop-color:#FCF7FC"/>
|
||||
<stop offset="0.2468" style="stop-color:#F2E1F2"/>
|
||||
<stop offset="0.4038" style="stop-color:#E3BEE2"/>
|
||||
<stop offset="0.5839" style="stop-color:#CE8CCD"/>
|
||||
<stop offset="0.7837" style="stop-color:#B24DB1"/>
|
||||
<stop offset="0.9971" style="stop-color:#91018F"/>
|
||||
<stop offset="1" style="stop-color:#91008F"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_PI2" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_PI2_3_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.632,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
C9,18.824,18.842,8.976,48,8.976S87,18.824,87,48C87,77.176,77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="VIOLET_2_2_">
|
||||
<linearGradient id="VIOLET_2_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.0107" x2="47.9995" y2="90.757">
|
||||
<stop offset="0.0364" style="stop-color:#BA66E0"/>
|
||||
<stop offset="0.2174" style="stop-color:#B260D8"/>
|
||||
<stop offset="0.497" style="stop-color:#9D51C2"/>
|
||||
<stop offset="0.8385" style="stop-color:#7C379F"/>
|
||||
<stop offset="1" style="stop-color:#69298C"/>
|
||||
</linearGradient>
|
||||
<path id="VIOLET_2_1_" display="inline" fill="url(#VIOLET_2_3_)" d="M8,47.989c0,29.633,10.365,40,40,40
|
||||
c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_VIO2_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2554" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.1299" style="stop-color:#F9F7FB"/>
|
||||
<stop offset="0.2745" style="stop-color:#EAE1EF"/>
|
||||
<stop offset="0.452" style="stop-color:#D1BEDC"/>
|
||||
<stop offset="0.6558" style="stop-color:#AF8CC1"/>
|
||||
<stop offset="0.8786" style="stop-color:#834EA0"/>
|
||||
<stop offset="1" style="stop-color:#69298C"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_VIO2" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_VIO2_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.632,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
C9,18.824,18.842,8.976,48,8.976S87,18.824,87,48C87,77.176,77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
<g id="VIOLET_1_2_">
|
||||
<linearGradient id="VIOLET_1_3_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="9.7622" x2="47.9995" y2="89.7412">
|
||||
<stop offset="0.0364" style="stop-color:#A14DDB"/>
|
||||
<stop offset="0.2205" style="stop-color:#9949D3"/>
|
||||
<stop offset="0.505" style="stop-color:#833CBE"/>
|
||||
<stop offset="0.8523" style="stop-color:#60299D"/>
|
||||
<stop offset="1" style="stop-color:#4F1F8C"/>
|
||||
</linearGradient>
|
||||
<path id="VIOLET_1_1_" display="inline" fill="url(#VIOLET_1_3_)" d="M8,47.989c0,29.633,10.365,40,40,40
|
||||
c29.637,0,40-10.367,40-40c0-28.985-9.926-39.53-38.091-39.979h-3.817C17.928,8.459,8,19.004,8,47.989z"/>
|
||||
<linearGradient id="HIGHLIGHT_VIO1_1_" gradientUnits="userSpaceOnUse" x1="47.9995" y1="8.2554" x2="47.9995" y2="87.5043">
|
||||
<stop offset="0.0364" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="1" style="stop-color:#4A1F8C"/>
|
||||
</linearGradient>
|
||||
<path id="HIGHLIGHT_VIO1" display="inline" opacity="0.25" fill="url(#HIGHLIGHT_VIO1_1_)" d="M48,8C18.365,8,8,18.365,8,48
|
||||
c0,29.632,10.365,40,40,40c29.637,0,40-10.367,40-40C88,18.365,77.637,8,48,8z M48,87.023C18.842,87.023,9,77.176,9,48
|
||||
C9,18.824,18.842,8.977,48,8.977S87,18.824,87,48C87,77.176,77.158,87.023,48,87.023z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="PLACE_YOUR_GRAPHIC_HERE">
|
||||
<g>
|
||||
<path opacity="0.05" d="M43.982,80.064c-1.382,0.277-2.732-0.619-3.008-2.004l-3.005-15.02c-1.096,0.221-4.489,0.902-15.014,3.006
|
||||
c-1.383,0.277-2.732-0.621-3.009-2.004l-4.011-20.06c-0.277-1.382,0.624-2.732,2.006-3.009l15.015-3.003l-3.002-15.015
|
||||
c-0.277-1.382,0.623-2.732,2.005-3.008l20.06-4.013c1.383-0.276,2.732,0.624,3.008,2.006c2.105,10.525,2.782,13.918,3.001,15.016
|
||||
l15.018-3.004c1.384-0.276,2.733,0.624,3.009,2.006l4.013,20.058c0.275,1.383-0.622,2.732-2.006,3.01
|
||||
c-10.536,2.105-13.923,2.781-15.019,3c0.22,1.096,0.898,4.482,3.006,15.018c0.277,1.383-0.622,2.732-2.005,3.01L43.982,80.064z"/>
|
||||
<path opacity="0.05" d="M43.883,79.564c-1.107,0.221-2.187-0.498-2.408-1.604l-3.081-15.406c-0.007-0.037-0.015-0.078-0.019-0.113
|
||||
c-0.038,0.008-15.52,3.105-15.52,3.105c-1.107,0.221-2.186-0.498-2.407-1.604l-4.011-20.06c-0.223-1.106,0.498-2.186,1.603-2.408
|
||||
l15.406-3.081c0.038-0.008,0.076-0.015,0.115-0.02c-0.011-0.038-0.019-0.076-0.026-0.114l-3.081-15.405
|
||||
c-0.222-1.106,0.497-2.186,1.604-2.407l20.06-4.012c1.105-0.222,2.187,0.498,2.406,1.604c0,0,3.096,15.481,3.103,15.52
|
||||
c0.037-0.01,0.076-0.018,0.113-0.025l15.405-3.082c1.106-0.221,2.185,0.499,2.406,1.605l4.013,20.06
|
||||
c0.221,1.105-0.499,2.184-1.604,2.406c0,0-15.482,3.096-15.521,3.1c0.008,0.039,3.105,15.521,3.105,15.521
|
||||
c0.222,1.104-0.497,2.184-1.604,2.406L43.883,79.564z M48.106,48.531c0.217-0.043,0.437-0.051,0.653-0.025
|
||||
c-0.218-0.381-0.308-0.827-0.254-1.263c-0.188,0.107-0.393,0.184-0.611,0.228c-0.217,0.043-0.437,0.051-0.652,0.025
|
||||
c0.219,0.382,0.306,0.826,0.253,1.264C47.682,48.652,47.889,48.574,48.106,48.531z"/>
|
||||
<path opacity="0.05" d="M43.782,79.063c-0.83,0.166-1.639-0.375-1.804-1.203l-3.082-15.404c-0.07-0.35-0.014-0.715,0.152-1.027
|
||||
c-0.221,0.273-0.538,0.467-0.889,0.537l-15.404,3.08c-0.829,0.166-1.64-0.373-1.806-1.203l-4.011-20.059
|
||||
c-0.166-0.83,0.374-1.64,1.204-1.806l15.405-3.081c0.349-0.07,0.715-0.014,1.027,0.154c-0.274-0.223-0.468-0.539-0.539-0.89
|
||||
l-3.08-15.404c-0.166-0.83,0.373-1.64,1.203-1.806l20.06-4.012c0.828-0.167,1.638,0.374,1.803,1.204l3.082,15.404
|
||||
c0.071,0.35,0.014,0.714-0.151,1.026c0.224-0.273,0.539-0.466,0.888-0.536l15.405-3.081c0.83-0.166,1.64,0.374,1.806,1.203
|
||||
l4.011,20.06c0.166,0.83-0.372,1.639-1.203,1.805l-15.405,3.082c-0.348,0.07-0.712,0.014-1.024-0.152
|
||||
c0.273,0.225,0.465,0.539,0.534,0.889l3.08,15.404c0.167,0.83-0.372,1.639-1.202,1.805L43.782,79.063z M46.341,47.251
|
||||
c0.676,0.47,0.859,1.385,0.417,2.081l-7.442,11.693l7.935-11.367c0.226-0.324,0.566-0.547,0.956-0.625
|
||||
c0.392-0.078,0.79-0.004,1.126,0.211l11.673,7.428L49.658,48.75c-0.675-0.471-0.857-1.384-0.417-2.079l7.435-11.683L48.75,46.342
|
||||
c-0.226,0.325-0.566,0.547-0.957,0.626c-0.391,0.078-0.791,0.004-1.125-0.211l-11.702-7.445L46.341,47.251z"/>
|
||||
<path opacity="0.05" d="M43.681,78.561c-0.553,0.113-1.093-0.25-1.202-0.803l-3.083-15.404c-0.054-0.27,0.005-0.559,0.165-0.785
|
||||
l8.106-11.617c0.152-0.217,0.379-0.363,0.639-0.416c0.261-0.053,0.526-0.004,0.75,0.139l11.951,7.604
|
||||
c0.234,0.15,0.398,0.393,0.455,0.664l3.081,15.404c0.109,0.555-0.249,1.094-0.802,1.205L43.681,78.561z M62.354,56.604
|
||||
c-0.271,0.055-0.56-0.006-0.785-0.164L49.95,48.332c-0.45-0.314-0.571-0.924-0.277-1.387l7.604-11.952
|
||||
c0.149-0.234,0.392-0.4,0.664-0.455l15.404-3.081c0.554-0.111,1.092,0.249,1.204,0.802l4.011,20.059
|
||||
c0.111,0.553-0.248,1.092-0.803,1.203L62.354,56.604z M22.655,64.543c-0.553,0.111-1.092-0.248-1.204-0.803l-4.012-20.058
|
||||
c-0.11-0.553,0.25-1.092,0.803-1.204l15.405-3.081c0.271-0.054,0.559,0.006,0.786,0.165l11.616,8.108
|
||||
c0.452,0.313,0.574,0.923,0.278,1.386l-7.605,11.951c-0.147,0.234-0.39,0.4-0.661,0.455L22.655,64.543z M47.693,46.467
|
||||
c-0.26,0.052-0.526,0.003-0.75-0.14l-11.952-7.604c-0.233-0.149-0.399-0.39-0.454-0.662l-3.08-15.405
|
||||
c-0.111-0.553,0.249-1.093,0.802-1.204l20.058-4.012c0.554-0.111,1.095,0.25,1.203,0.802l3.082,15.405
|
||||
c0.056,0.272-0.004,0.559-0.164,0.787l-8.108,11.615C48.18,46.267,47.953,46.416,47.693,46.467z"/>
|
||||
<path opacity="0.1" d="M43.581,78.061c-0.278,0.055-0.545-0.125-0.602-0.402l-3.082-15.404c-0.027-0.137,0.003-0.279,0.083-0.395
|
||||
l8.107-11.617c0.078-0.109,0.194-0.182,0.319-0.207c0.124-0.023,0.259-0.004,0.374,0.07l11.952,7.605
|
||||
c0.117,0.074,0.199,0.193,0.229,0.33l3.08,15.406c0.056,0.275-0.125,0.547-0.403,0.6L43.581,78.061z M62.253,56.102
|
||||
c-0.137,0.027-0.278-0.002-0.394-0.08l-11.616-8.109c-0.224-0.156-0.285-0.462-0.14-0.693l7.606-11.952
|
||||
c0.075-0.118,0.193-0.199,0.33-0.227l15.406-3.081c0.276-0.056,0.547,0.124,0.6,0.401l4.014,20.06
|
||||
c0.056,0.275-0.124,0.547-0.401,0.6L62.253,56.102z M22.555,64.043c-0.277,0.057-0.547-0.125-0.603-0.402L17.94,43.582
|
||||
c-0.056-0.277,0.124-0.545,0.402-0.601l15.404-3.081c0.137-0.028,0.278,0.002,0.394,0.083l11.615,8.107
|
||||
c0.226,0.156,0.287,0.461,0.139,0.694L38.29,60.734c-0.075,0.117-0.194,0.199-0.33,0.229L22.555,64.043z M47.592,45.965
|
||||
c-0.123,0.025-0.258,0.004-0.373-0.069l-11.953-7.605c-0.119-0.074-0.2-0.194-0.228-0.331l-3.081-15.405
|
||||
c-0.056-0.277,0.125-0.546,0.402-0.602l20.058-4.012c0.277-0.055,0.547,0.124,0.604,0.401l3.081,15.404
|
||||
c0.026,0.138-0.002,0.279-0.084,0.394l-8.107,11.616C47.833,45.869,47.718,45.941,47.592,45.965z"/>
|
||||
<path fill="#5A7C8C" d="M48.865,50.01l11.95,7.604l3.082,15.403L43.839,77.03l-3.082-15.405L48.865,50.01z M47.85,44.937
|
||||
l8.107-11.617l-3.08-15.405l-20.06,4.011l3.081,15.406L47.85,44.937z M62.511,55.073l15.404-3.082l-4.013-20.058l-15.404,3.081
|
||||
l-7.604,11.952L62.511,55.073z M45.82,47.98l-11.617-8.108l-15.405,3.082l4.012,20.059l15.406-3.081L45.82,47.98z"/>
|
||||
<g>
|
||||
<polygon fill="#94C4D3" points="45.43,74.558 42.943,62.126 49.43,52.836 58.991,58.918 61.478,71.348 "/>
|
||||
<polygon fill="#94C4D3" points="35.238,23.596 37.724,36.028 47.285,42.11 53.772,32.818 51.285,20.387 "/>
|
||||
<polygon fill="#94C4D3" points="75.441,50.4 63.014,52.885 53.72,46.4 59.804,36.839 72.232,34.354 "/>
|
||||
<polygon fill="#94C4D3" points="24.48,60.593 36.913,58.106 42.994,48.545 33.702,42.059 21.27,44.545 "/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="DO_NOT_EDIT_-_FOCAL_ZONE_GUIDES_ONLY">
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
|
@ -0,0 +1,67 @@
|
|||
# For MSVC
|
||||
*.lastcodeanalysissucceeded
|
||||
*.pdb
|
||||
*.ilk
|
||||
*.obj
|
||||
*.pch
|
||||
*.log
|
||||
*.dll
|
||||
*.rar
|
||||
*.exe
|
||||
*.map
|
||||
*.lib
|
||||
*.user
|
||||
*.sdf
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.suo
|
||||
*.aps
|
||||
*.exp
|
||||
Debug
|
||||
Release
|
||||
Windows/x64
|
||||
Windows/ipch
|
||||
|
||||
# For Mac
|
||||
.DS_Store
|
||||
|
||||
# For ppsspp.ini, etc.
|
||||
ppsspp.ini
|
||||
PPSSPPControls.dat
|
||||
|
||||
# Qt Linguist files
|
||||
*.qm
|
||||
|
||||
Logs
|
||||
Memstick
|
||||
memstick
|
||||
Cheats
|
||||
|
||||
bin
|
||||
gen
|
||||
libs
|
||||
obj
|
||||
build*/
|
||||
/git-version.cpp
|
||||
|
||||
.pspsh.hist
|
||||
__testoutput.txt
|
||||
__testerror.txt
|
||||
__testfinish.txt
|
||||
__testfailure.bmp
|
||||
GameLogNotes.txt
|
||||
screenshots
|
||||
android/ui_atlas.zim
|
||||
android/assets/lang
|
||||
android/assets/flash0
|
||||
ppge_atlas.zim.png
|
||||
local.properties
|
||||
|
||||
# For vim
|
||||
*.swp
|
||||
tags
|
||||
|
||||
libat3plusdecoder.dylib
|
||||
libat3plusdecoder.so
|
||||
at3plusdecoder.dll
|
||||
at3plusdecoder64.dll
|
|
@ -0,0 +1,12 @@
|
|||
[submodule "native"]
|
||||
path = native
|
||||
url = https://github.com/hrydgard/native.git
|
||||
[submodule "pspautotests"]
|
||||
path = pspautotests
|
||||
url = https://github.com/hrydgard/pspautotests.git
|
||||
[submodule "lang"]
|
||||
path = lang
|
||||
url = https://github.com/hrydgard/ppsspp-lang.git
|
||||
[submodule "ffmpeg"]
|
||||
path = ffmpeg
|
||||
url = https://github.com/hrydgard/ppsspp-ffmpeg.git
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<qnx xmlns="http://www.qnx.com/schemas/application/1.0">
|
||||
<id>com.Qtness.PPSSPP</id>
|
||||
<name>PPSSPP</name>
|
||||
<filename>PPSSPPBlackberry</filename>
|
||||
<versionNumber>0.8.0</versionNumber>
|
||||
<buildId>1</buildId>
|
||||
<description>Playstation portable emulator.</description>
|
||||
|
||||
<author>Qtness</author>
|
||||
<authorId>gYAAgGE4qaHzBnzEAu8JKe4G1OI</authorId>
|
||||
|
||||
<initialWindow>
|
||||
<aspectRatio>landscape</aspectRatio>
|
||||
<autoOrients>false</autoOrients>
|
||||
<systemChrome>none</systemChrome>
|
||||
<transparent>false</transparent>
|
||||
</initialWindow>
|
||||
|
||||
<asset path="PPSSPPBlackberry" entry="true" type="Qnx/Elf">PPSSPPBlackberry</asset>
|
||||
<asset path="../assets/icon-114.png">icon-114.png</asset>
|
||||
<asset path="../android/assets">assets</asset>
|
||||
<asset path="../lang">assets/lang</asset>
|
||||
<asset path="../flash0">assets/flash</asset>
|
||||
|
||||
<category>core.games</category>
|
||||
<icon>
|
||||
<image>icon-114.png</image>
|
||||
</icon>
|
||||
|
||||
<splashscreen>icon-114.png</splashscreen>
|
||||
|
||||
<action system="true">run_native</action>
|
||||
<action>access_shared</action>
|
||||
<action>play_audio</action>
|
||||
</qnx>
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
BB_OS=`cat ${QNX_TARGET}/etc/qversion 2>/dev/null`
|
||||
if [ -z "$BB_OS" ]; then
|
||||
echo "Could not find your Blackberry NDK. Please source bbndk-env.sh"
|
||||
exit 1
|
||||
fi
|
||||
echo "Building for Blackberry ${BB_OS}"
|
||||
|
||||
# Set up cmake with GCC 4.6.3 cross-compiler from PATH
|
||||
CC=ntoarmv7-gcc CXX=ntoarmv7-g++ cmake -DBLACKBERRY=${BB_OS} ..
|
||||
|
||||
# Compile and create unsigned PPSSPP.bar with debugtoken
|
||||
DEBUG="-devMode -debugToken ${HOME}/debugtoken.bar"
|
||||
make -j4 && blackberry-nativepackager -package PPSSPP.bar bar-descriptor.xml $DEBUG
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,610 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
// Shared code between Win64 and Unix64
|
||||
|
||||
// Sets up a __cdecl function.
|
||||
void XEmitter::ABI_EmitPrologue(int maxCallParams)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
// Don't really need to do anything
|
||||
#elif defined(_M_X64)
|
||||
#if _WIN32
|
||||
int stacksize = ((maxCallParams + 1) & ~1) * 8 + 8;
|
||||
// Set up a stack frame so that we can call functions
|
||||
// TODO: use maxCallParams
|
||||
SUB(64, R(RSP), Imm8(stacksize));
|
||||
#endif
|
||||
#else
|
||||
#error Arch not supported
|
||||
#endif
|
||||
}
|
||||
|
||||
void XEmitter::ABI_EmitEpilogue(int maxCallParams)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
RET();
|
||||
#elif defined(_M_X64)
|
||||
#ifdef _WIN32
|
||||
int stacksize = ((maxCallParams+1)&~1)*8 + 8;
|
||||
ADD(64, R(RSP), Imm8(stacksize));
|
||||
#endif
|
||||
RET();
|
||||
#else
|
||||
#error Arch not supported
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _M_IX86 // All32
|
||||
|
||||
// Shared code between Win32 and Unix32
|
||||
void XEmitter::ABI_CallFunction(void *func) {
|
||||
ABI_AlignStack(0);
|
||||
CALL(func);
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC16(void *func, u16 param1) {
|
||||
ABI_AlignStack(1 * 2);
|
||||
PUSH(16, Imm16(param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(1 * 2);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC16(void *func, u32 param1, u16 param2) {
|
||||
ABI_AlignStack(1 * 2 + 1 * 4);
|
||||
PUSH(16, Imm16(param2));
|
||||
PUSH(32, Imm32(param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(1 * 2 + 1 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC(void *func, u32 param1) {
|
||||
ABI_AlignStack(1 * 4);
|
||||
PUSH(32, Imm32(param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(1 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
|
||||
ABI_AlignStack(2 * 4);
|
||||
PUSH(32, Imm32(param2));
|
||||
PUSH(32, Imm32(param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(2 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param3) {
|
||||
ABI_AlignStack(3 * 4);
|
||||
PUSH(32, Imm32(param3));
|
||||
PUSH(32, Imm32(param2));
|
||||
PUSH(32, Imm32(param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(3 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCP(void *func, u32 param1, u32 param2, void *param3) {
|
||||
ABI_AlignStack(3 * 4);
|
||||
PUSH(32, Imm32((u32)param3));
|
||||
PUSH(32, Imm32(param2));
|
||||
PUSH(32, Imm32(param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(3 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2,u32 param3, void *param4) {
|
||||
ABI_AlignStack(4 * 4);
|
||||
PUSH(32, Imm32((u32)param4));
|
||||
PUSH(32, Imm32(param3));
|
||||
PUSH(32, Imm32(param2));
|
||||
PUSH(32, Imm32(param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(4 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2,u32 param3) {
|
||||
ABI_AlignStack(3 * 4);
|
||||
PUSH(32, Imm32(param3));
|
||||
PUSH(32, Imm32((u32)param2));
|
||||
PUSH(32, Imm32((u32)param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(3 * 4);
|
||||
}
|
||||
|
||||
// Pass a register as a parameter.
|
||||
void XEmitter::ABI_CallFunctionR(void *func, X64Reg reg1) {
|
||||
ABI_AlignStack(1 * 4);
|
||||
PUSH(32, R(reg1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(1 * 4);
|
||||
}
|
||||
|
||||
// Pass two registers as parameters.
|
||||
void XEmitter::ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2)
|
||||
{
|
||||
ABI_AlignStack(2 * 4);
|
||||
PUSH(32, R(reg2));
|
||||
PUSH(32, R(reg1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(2 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
||||
{
|
||||
ABI_AlignStack(2 * 4);
|
||||
PUSH(32, Imm32(param2));
|
||||
PUSH(32, arg1);
|
||||
CALL(func);
|
||||
ABI_RestoreStack(2 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionACC(void *func, const Gen::OpArg &arg1, u32 param2, u32 param3)
|
||||
{
|
||||
ABI_AlignStack(3 * 4);
|
||||
PUSH(32, Imm32(param3));
|
||||
PUSH(32, Imm32(param2));
|
||||
PUSH(32, arg1);
|
||||
CALL(func);
|
||||
ABI_RestoreStack(3 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1)
|
||||
{
|
||||
ABI_AlignStack(1 * 4);
|
||||
PUSH(32, arg1);
|
||||
CALL(func);
|
||||
ABI_RestoreStack(1 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionAA(void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2)
|
||||
{
|
||||
ABI_AlignStack(2 * 4);
|
||||
PUSH(32, arg2);
|
||||
PUSH(32, arg1);
|
||||
CALL(func);
|
||||
ABI_RestoreStack(2 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||
// Note: 4 * 4 = 16 bytes, so alignment is preserved.
|
||||
PUSH(EBP);
|
||||
PUSH(EBX);
|
||||
PUSH(ESI);
|
||||
PUSH(EDI);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||
POP(EDI);
|
||||
POP(ESI);
|
||||
POP(EBX);
|
||||
POP(EBP);
|
||||
}
|
||||
|
||||
unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
||||
frameSize += 4; // reserve space for return address
|
||||
unsigned int alignedSize =
|
||||
#ifdef __GNUC__
|
||||
(frameSize + 15) & -16;
|
||||
#else
|
||||
(frameSize + 3) & -4;
|
||||
#endif
|
||||
return alignedSize;
|
||||
}
|
||||
|
||||
|
||||
void XEmitter::ABI_AlignStack(unsigned int frameSize) {
|
||||
// Mac OS X requires the stack to be 16-byte aligned before every call.
|
||||
// Linux requires the stack to be 16-byte aligned before calls that put SSE
|
||||
// vectors on the stack, but since we do not keep track of which calls do that,
|
||||
// it is effectively every call as well.
|
||||
// Windows binaries compiled with MSVC do not have such a restriction*, but I
|
||||
// expect that GCC on Windows acts the same as GCC on Linux in this respect.
|
||||
// It would be nice if someone could verify this.
|
||||
// *However, the MSVC optimizing compiler assumes a 4-byte-aligned stack at times.
|
||||
unsigned int fillSize =
|
||||
ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
|
||||
if (fillSize != 0) {
|
||||
SUB(32, R(ESP), Imm8(fillSize));
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_RestoreStack(unsigned int frameSize) {
|
||||
unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize);
|
||||
alignedSize -= 4; // return address is POPped at end of call
|
||||
if (alignedSize != 0) {
|
||||
ADD(32, R(ESP), Imm8(alignedSize));
|
||||
}
|
||||
}
|
||||
|
||||
#else //64bit
|
||||
|
||||
// Common functions
|
||||
void XEmitter::ABI_CallFunction(void *func) {
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC16(void *func, u16 param1) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32((u32)param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC16(void *func, u32 param1, u16 param2) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32((u32)param2));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC(void *func, u32 param1) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param3) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCP(void *func, u32 param1, u32 param2, void *param3) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(64, R(ABI_PARAM3), Imm64((u64)param3));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 param3, void *param4) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
MOV(64, R(ABI_PARAM4), Imm64((u64)param4));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3) {
|
||||
MOV(64, R(ABI_PARAM1), Imm64((u64)param1));
|
||||
MOV(64, R(ABI_PARAM2), Imm64((u64)param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass a register as a parameter.
|
||||
void XEmitter::ABI_CallFunctionR(void *func, X64Reg reg1) {
|
||||
if (reg1 != ABI_PARAM1)
|
||||
MOV(32, R(ABI_PARAM1), R(reg1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass two registers as parameters.
|
||||
void XEmitter::ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2) {
|
||||
if (reg2 != ABI_PARAM1) {
|
||||
if (reg1 != ABI_PARAM1)
|
||||
MOV(64, R(ABI_PARAM1), R(reg1));
|
||||
if (reg2 != ABI_PARAM2)
|
||||
MOV(64, R(ABI_PARAM2), R(reg2));
|
||||
} else {
|
||||
if (reg2 != ABI_PARAM2)
|
||||
MOV(64, R(ABI_PARAM2), R(reg2));
|
||||
if (reg1 != ABI_PARAM1)
|
||||
MOV(64, R(ABI_PARAM1), R(reg1));
|
||||
}
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
||||
{
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionACC(void *func, const Gen::OpArg &arg1, u32 param2, u32 param3)
|
||||
{
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(64, R(ABI_PARAM3), Imm64(param3));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1)
|
||||
{
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionAA(void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2)
|
||||
{
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
if (!arg2.IsSimpleReg(ABI_PARAM2))
|
||||
MOV(32, R(ABI_PARAM2), arg2);
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
||||
return frameSize;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// The Windows x64 ABI requires XMM6 - XMM15 to be callee saved. 10 regs.
|
||||
const int XMM_STACK_SPACE = 10 * 16;
|
||||
|
||||
// Win64 Specific Code
|
||||
void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||
//we only want to do this once
|
||||
PUSH(RBX);
|
||||
PUSH(RSI);
|
||||
PUSH(RDI);
|
||||
PUSH(RBP);
|
||||
PUSH(R12);
|
||||
PUSH(R13);
|
||||
PUSH(R14);
|
||||
PUSH(R15);
|
||||
ABI_AlignStack(0);
|
||||
|
||||
// Do this after aligning, beacuse before it's offset by 8.
|
||||
SUB(64, R(RSP), Imm32(XMM_STACK_SPACE));
|
||||
for (int i = 0; i < 10; ++i)
|
||||
MOVAPS(MDisp(RSP, i * 16), (X64Reg)(XMM6 + i));
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||
for (int i = 0; i < 10; ++i)
|
||||
MOVAPS((X64Reg)(XMM6 + i), MDisp(RSP, i * 16));
|
||||
ADD(64, R(RSP), Imm32(XMM_STACK_SPACE));
|
||||
|
||||
ABI_RestoreStack(0);
|
||||
POP(R15);
|
||||
POP(R14);
|
||||
POP(R13);
|
||||
POP(R12);
|
||||
POP(RBP);
|
||||
POP(RDI);
|
||||
POP(RSI);
|
||||
POP(RBX);
|
||||
}
|
||||
|
||||
// Win64 Specific Code
|
||||
void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||
PUSH(RCX);
|
||||
PUSH(RDX);
|
||||
PUSH(RSI);
|
||||
PUSH(RDI);
|
||||
PUSH(R8);
|
||||
PUSH(R9);
|
||||
PUSH(R10);
|
||||
PUSH(R11);
|
||||
// Callers preserve XMM4-5 (XMM0-3 are args.) But we don't need them usually.
|
||||
ABI_AlignStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||
ABI_RestoreStack(0);
|
||||
POP(R11);
|
||||
POP(R10);
|
||||
POP(R9);
|
||||
POP(R8);
|
||||
POP(RDI);
|
||||
POP(RSI);
|
||||
POP(RDX);
|
||||
POP(RCX);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) {
|
||||
SUB(64, R(RSP), Imm8(0x28));
|
||||
}
|
||||
|
||||
void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) {
|
||||
ADD(64, R(RSP), Imm8(0x28));
|
||||
}
|
||||
|
||||
#else
|
||||
// Unix64 Specific Code
|
||||
void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||
PUSH(RBX);
|
||||
PUSH(RBP);
|
||||
PUSH(R12);
|
||||
PUSH(R13);
|
||||
PUSH(R14);
|
||||
PUSH(R15);
|
||||
PUSH(R15); //just to align stack. duped push/pop doesn't hurt.
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||
POP(R15);
|
||||
POP(R15);
|
||||
POP(R14);
|
||||
POP(R13);
|
||||
POP(R12);
|
||||
POP(RBP);
|
||||
POP(RBX);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||
PUSH(RCX);
|
||||
PUSH(RDX);
|
||||
PUSH(RSI);
|
||||
PUSH(RDI);
|
||||
PUSH(R8);
|
||||
PUSH(R9);
|
||||
PUSH(R10);
|
||||
PUSH(R11);
|
||||
PUSH(R11);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||
POP(R11);
|
||||
POP(R11);
|
||||
POP(R10);
|
||||
POP(R9);
|
||||
POP(R8);
|
||||
POP(RDI);
|
||||
POP(RSI);
|
||||
POP(RDX);
|
||||
POP(RCX);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) {
|
||||
SUB(64, R(RSP), Imm8(0x08));
|
||||
}
|
||||
|
||||
void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) {
|
||||
ADD(64, R(RSP), Imm8(0x08));
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#endif // 32bit
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _JIT_ABI_H_
|
||||
#define _JIT_ABI_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
// x86/x64 ABI:s, and helpers to help follow them when JIT-ing code.
|
||||
// All convensions return values in EAX (+ possibly EDX).
|
||||
|
||||
// Linux 32-bit, Windows 32-bit (cdecl, System V):
|
||||
// * Caller pushes left to right
|
||||
// * Caller fixes stack after call
|
||||
// * function subtract from stack for local storage only.
|
||||
// Scratch: EAX ECX EDX
|
||||
// Callee-save: EBX ESI EDI EBP
|
||||
// Parameters: -
|
||||
|
||||
// Windows 64-bit
|
||||
// * 4-reg "fastcall" variant, very new-skool stack handling
|
||||
// * Callee moves stack pointer, to make room for shadow regs for the biggest function _it itself calls_
|
||||
// * Parameters passed in RCX, RDX, ... further parameters are MOVed into the allocated stack space.
|
||||
// Scratch: RAX RCX RDX R8 R9 R10 R11
|
||||
// Callee-save: RBX RSI RDI RBP R12 R13 R14 R15
|
||||
// Parameters: RCX RDX R8 R9, further MOV-ed
|
||||
|
||||
// Linux 64-bit
|
||||
// * 6-reg "fastcall" variant, old skool stack handling (parameters are pushed)
|
||||
// Scratch: RAX RCX RDX RSI RDI R8 R9 R10 R11
|
||||
// Callee-save: RBX RBP R12 R13 R14 R15
|
||||
// Parameters: RDI RSI RDX RCX R8 R9
|
||||
|
||||
#ifdef _M_IX86 // 32 bit calling convention, shared by all
|
||||
|
||||
// 32-bit don't pass parameters in regs, but these are convenient to have anyway when we have to
|
||||
// choose regs to put stuff in.
|
||||
#define ABI_PARAM1 RCX
|
||||
#define ABI_PARAM2 RDX
|
||||
|
||||
// There are no ABI_PARAM* here, since args are pushed.
|
||||
// 32-bit bog standard cdecl, shared between linux and windows
|
||||
// MacOSX 32-bit is same as System V with a few exceptions that we probably don't care much about.
|
||||
|
||||
#elif _M_X64 // 64 bit calling convention
|
||||
|
||||
#ifdef _WIN32 // 64-bit Windows - the really exotic calling convention
|
||||
|
||||
#define ABI_PARAM1 RCX
|
||||
#define ABI_PARAM2 RDX
|
||||
#define ABI_PARAM3 R8
|
||||
#define ABI_PARAM4 R9
|
||||
|
||||
#else //64-bit Unix (hopefully MacOSX too)
|
||||
|
||||
#define ABI_PARAM1 RDI
|
||||
#define ABI_PARAM2 RSI
|
||||
#define ABI_PARAM3 RDX
|
||||
#define ABI_PARAM4 RCX
|
||||
#define ABI_PARAM5 R8
|
||||
#define ABI_PARAM6 R9
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#endif // X86
|
||||
|
||||
#endif // _JIT_ABI_H_
|
||||
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
// 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 "ArmEmitter.h"
|
||||
#include "ArmABI.h"
|
||||
|
||||
using namespace ArmGen;
|
||||
// If passing arguments, don't use this.
|
||||
void ARMXEmitter::ARMABI_CallFunction(void *func)
|
||||
{
|
||||
PUSH(5, R0, R1, R2, R3, _LR);
|
||||
ARMABI_MOVI2R(R14, (u32)func);
|
||||
BL(R14);
|
||||
POP(5, R0, R1, R2, R3, _LR);
|
||||
}
|
||||
void ARMXEmitter::ARMABI_CallFunctionC(void *func, u32 Arg)
|
||||
{
|
||||
PUSH(5, R0, R1, R2, R3, _LR);
|
||||
ARMABI_MOVI2R(R14, (u32)func);
|
||||
ARMABI_MOVI2R(R0, Arg);
|
||||
BL(R14);
|
||||
POP(5, R0, R1, R2, R3, _LR);
|
||||
}
|
||||
|
||||
void ARMXEmitter::ARMABI_CallFunctionCNoSave(void *func, u32 Arg)
|
||||
{
|
||||
PUSH(1, _LR);
|
||||
ARMABI_MOVI2R(R14, (u32)func);
|
||||
ARMABI_MOVI2R(R0, Arg);
|
||||
BL(R14);
|
||||
POP(1, _LR);
|
||||
}
|
||||
|
||||
void ARMXEmitter::ARMABI_CallFunctionCC(void *func, u32 Arg1, u32 Arg2)
|
||||
{
|
||||
PUSH(5, R0, R1, R2, R3, _LR);
|
||||
ARMABI_MOVI2R(R14, (u32)func);
|
||||
ARMABI_MOVI2R(R0, Arg1);
|
||||
ARMABI_MOVI2R(R1, Arg2);
|
||||
BL(R14);
|
||||
POP(5, R0, R1, R2, R3, _LR);
|
||||
|
||||
}
|
||||
void ARMXEmitter::ARMABI_CallFunctionCCC(void *func, u32 Arg1, u32 Arg2, u32 Arg3)
|
||||
{
|
||||
PUSH(5, R0, R1, R2, R3, _LR);
|
||||
ARMABI_MOVI2R(R14, (u32)func);
|
||||
ARMABI_MOVI2R(R0, Arg1);
|
||||
ARMABI_MOVI2R(R1, Arg2);
|
||||
ARMABI_MOVI2R(R2, Arg3);
|
||||
BL(R14);
|
||||
POP(5, R0, R1, R2, R3, _LR);
|
||||
}
|
||||
|
||||
void ARMXEmitter::ARMABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||
// Note: 4 * 4 = 16 bytes, so alignment is preserved.
|
||||
PUSH(4, R0, R1, R2, R3);
|
||||
}
|
||||
|
||||
void ARMXEmitter::ARMABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||
POP(4, R0, R1, R2, R3);
|
||||
}
|
||||
|
||||
const char *conditions[] = {"EQ", "NEQ", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "AL" };
|
||||
static void ShowCondition(u32 cond)
|
||||
{
|
||||
printf("Condition: %s[%d]\n", conditions[cond], cond);
|
||||
}
|
||||
void ARMXEmitter::ARMABI_ShowConditions()
|
||||
{
|
||||
const u8 *ptr = GetCodePtr();
|
||||
FixupBranch cc[15];
|
||||
for(u32 a = 0; a < 15; ++a)
|
||||
cc[a] = B_CC((CCFlags)a);
|
||||
|
||||
for(u32 a = 0; a < 15; ++a)
|
||||
{
|
||||
SetJumpTarget(cc[a]);
|
||||
ARMABI_CallFunctionC((void*)&ShowCondition, a);
|
||||
if(a != 14)
|
||||
B(ptr + ((a + 1) * 4));
|
||||
}
|
||||
}
|
||||
// NZCVQ is stored in the lower five bits of the Flags variable
|
||||
// GE values are in the lower four bits of the GEval variable
|
||||
|
||||
void ARMXEmitter::UpdateAPSR(bool NZCVQ, u8 Flags, bool GE, u8 GEval)
|
||||
{
|
||||
if(NZCVQ && GE)
|
||||
{
|
||||
// Can't update GE with the other ones with a immediate
|
||||
// Got to use a scratch register
|
||||
u32 Imm = (Flags << 27) | ((GEval & 0xF) << 16);
|
||||
ARMABI_MOVI2R(R14, Imm);
|
||||
_MSR(true, true, R14);
|
||||
}
|
||||
else
|
||||
if(NZCVQ)
|
||||
{
|
||||
Operand2 value(Flags << 1, 3);
|
||||
_MSR(true, false, value);
|
||||
}
|
||||
else if(GE)
|
||||
{
|
||||
Operand2 value(GEval << 2, 9);
|
||||
_MSR(false, true, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// 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/
|
||||
|
||||
#ifndef _JIT_ARMABI_H_
|
||||
#define _JIT_ARMABI_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
// I've been using R8 as a trash register, I don't know if I should choose a
|
||||
// better register or statically allocate some later, for now I'll just thrash
|
||||
// R8 and down the road think about the other ones.
|
||||
// TODO: Look at what all registers are being used for.
|
||||
|
||||
// ARMv7 uses registers for arguments to instructions
|
||||
// R0 is also used for returns from instructions
|
||||
// R1 is used as return along with R0 if it is a double size
|
||||
|
||||
#define ARM_PARAM1 R0
|
||||
#define ARM_PARAM2 R1
|
||||
#define ARM_PARAM3 R2
|
||||
#define ARM_PARAM4 R3
|
||||
#endif
|
|
@ -0,0 +1,227 @@
|
|||
// 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"
|
||||
#include "StringUtils.h"
|
||||
|
||||
// Only Linux platforms have /proc/cpuinfo
|
||||
#if !defined(BLACKBERRY) && !defined(IOS) && !defined(__SYMBIAN32__)
|
||||
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];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(procfile, "r");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
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
|
||||
// INFO_LOG(BOOT, "CPU: %s", cpu_string);
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return cpu_string;
|
||||
}
|
||||
bool CheckCPUFeature(const char *feature)
|
||||
{
|
||||
const char marker[] = "Features\t: ";
|
||||
char buf[1024];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(procfile, "r");
|
||||
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))
|
||||
{
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
token = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
int GetCoreCount()
|
||||
{
|
||||
#ifdef __SYMBIAN32__
|
||||
return 1;
|
||||
#elif defined(BLACKBERRY) || defined(IOS)
|
||||
return 2;
|
||||
#else
|
||||
const char marker[] = "processor\t: ";
|
||||
int cores = 0;
|
||||
char buf[1024];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(procfile, "r");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
{
|
||||
if (strncmp(buf, marker, sizeof(marker) - 1))
|
||||
continue;
|
||||
++cores;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return cores;
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
Mode64bit = false;
|
||||
vendor = VENDOR_ARM;
|
||||
|
||||
// Get the information about the CPU
|
||||
num_cores = GetCoreCount();
|
||||
#if defined(__SYMBIAN32__) || defined(BLACKBERRY) || defined(IOS)
|
||||
bool isVFP3 = false;
|
||||
bool isVFP4 = false;
|
||||
#ifdef IOS
|
||||
isVFP3 = true;
|
||||
// TODO: Check for swift arch (VFP4)
|
||||
#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));
|
||||
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");
|
||||
// These two require ARMv8 or higher
|
||||
bFP = CheckCPUFeature("fp");
|
||||
bASIMD = CheckCPUFeature("asimd");
|
||||
#endif
|
||||
// On android, we build a separate library for ARMv7 so this is fine.
|
||||
// TODO: Check for ARMv7 on other platforms.
|
||||
#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;
|
||||
#if defined(BLACKBERRY) || defined(IOS) || defined(__SYMBIAN32__)
|
||||
sum = StringFromFormat("%i cores", num_cores);
|
||||
#else
|
||||
if (num_cores == 1)
|
||||
sum = StringFromFormat("%s, %i core", cpu_string, num_cores);
|
||||
else
|
||||
sum = StringFromFormat("%s, %i cores", cpu_string, num_cores);
|
||||
#endif
|
||||
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";
|
||||
if (bIDIVa) sum += ", IDIVa";
|
||||
if (bIDIVt) sum += ", IDIVt";
|
||||
|
||||
return sum;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,661 @@
|
|||
// 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/
|
||||
|
||||
// WARNING - THIS LIBRARY IS NOT THREAD SAFE!!!
|
||||
|
||||
#ifndef _DOLPHIN_ARM_CODEGEN_
|
||||
#define _DOLPHIN_ARM_CODEGEN_
|
||||
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
#if defined(__SYMBIAN32__) || defined(PANDORA)
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#include <vector>
|
||||
|
||||
#undef _IP
|
||||
#undef R0
|
||||
#undef _SP
|
||||
#undef _LR
|
||||
#undef _PC
|
||||
|
||||
// VCVT flags
|
||||
#define TO_FLOAT 0
|
||||
#define TO_INT 1 << 0
|
||||
#define IS_SIGNED 1 << 1
|
||||
#define ROUND_TO_ZERO 1 << 2
|
||||
|
||||
namespace ArmGen
|
||||
{
|
||||
enum ARMReg
|
||||
{
|
||||
// GPRs
|
||||
R0 = 0, R1, R2, R3, R4, R5,
|
||||
R6, R7, R8, R9, R10, R11,
|
||||
|
||||
// SPRs
|
||||
// R13 - R15 are SP, LR, and PC.
|
||||
// Almost always referred to by name instead of register number
|
||||
R12 = 12, R13 = 13, R14 = 14, R15 = 15,
|
||||
_IP = 12, _SP = 13, _LR = 14, _PC = 15,
|
||||
|
||||
|
||||
// VFP single precision registers
|
||||
S0, S1, S2, S3, S4, S5, S6,
|
||||
S7, S8, S9, S10, S11, S12, S13,
|
||||
S14, S15, S16, S17, S18, S19, S20,
|
||||
S21, S22, S23, S24, S25, S26, S27,
|
||||
S28, S29, S30, S31,
|
||||
|
||||
// VFP Double Precision registers
|
||||
D0, D1, D2, D3, D4, D5, D6, D7,
|
||||
D8, D9, D10, D11, D12, D13, D14, D15,
|
||||
D16, D17, D18, D19, D20, D21, D22, D23,
|
||||
D24, D25, D26, D27, D28, D29, D30, D31,
|
||||
|
||||
// ASIMD Quad-Word registers
|
||||
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
|
||||
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
|
||||
INVALID_REG = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum CCFlags
|
||||
{
|
||||
CC_EQ = 0, // Equal
|
||||
CC_NEQ, // Not equal
|
||||
CC_CS, // Carry Set
|
||||
CC_CC, // Carry Clear
|
||||
CC_MI, // Minus (Negative)
|
||||
CC_PL, // Plus
|
||||
CC_VS, // Overflow
|
||||
CC_VC, // No Overflow
|
||||
CC_HI, // Unsigned higher
|
||||
CC_LS, // Unsigned lower or same
|
||||
CC_GE, // Signed greater than or equal
|
||||
CC_LT, // Signed less than
|
||||
CC_GT, // Signed greater than
|
||||
CC_LE, // Signed less than or equal
|
||||
CC_AL, // Always (unconditional) 14
|
||||
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
|
||||
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
|
||||
};
|
||||
const u32 NO_COND = 0xE0000000;
|
||||
|
||||
enum ShiftType
|
||||
{
|
||||
ST_LSL = 0,
|
||||
ST_ASL = 0,
|
||||
ST_LSR = 1,
|
||||
ST_ASR = 2,
|
||||
ST_ROR = 3,
|
||||
ST_RRX = 4
|
||||
};
|
||||
enum IntegerSize
|
||||
{
|
||||
I_I8 = 0,
|
||||
I_I16,
|
||||
I_I32,
|
||||
I_I64
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NUMGPRs = 13,
|
||||
};
|
||||
|
||||
class ARMXEmitter;
|
||||
|
||||
enum OpType
|
||||
{
|
||||
TYPE_IMM = 0,
|
||||
TYPE_REG,
|
||||
TYPE_IMMSREG,
|
||||
TYPE_RSR,
|
||||
TYPE_MEM
|
||||
};
|
||||
|
||||
// This is no longer a proper operand2 class. Need to split up.
|
||||
class Operand2
|
||||
{
|
||||
friend class ARMXEmitter;
|
||||
protected:
|
||||
u32 Value;
|
||||
|
||||
private:
|
||||
OpType Type;
|
||||
|
||||
// IMM types
|
||||
u8 Rotation; // Only for u8 values
|
||||
|
||||
// Register types
|
||||
u8 IndexOrShift;
|
||||
ShiftType Shift;
|
||||
public:
|
||||
OpType GetType()
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
Operand2() {}
|
||||
Operand2(u32 imm, OpType type = TYPE_IMM)
|
||||
{
|
||||
Type = type;
|
||||
Value = imm;
|
||||
Rotation = 0;
|
||||
}
|
||||
|
||||
Operand2(ARMReg Reg)
|
||||
{
|
||||
Type = TYPE_REG;
|
||||
Value = Reg;
|
||||
Rotation = 0;
|
||||
}
|
||||
Operand2(u8 imm, u8 rotation)
|
||||
{
|
||||
Type = TYPE_IMM;
|
||||
Value = imm;
|
||||
Rotation = rotation;
|
||||
}
|
||||
Operand2(ARMReg base, ShiftType type, ARMReg shift) // RSR
|
||||
{
|
||||
Type = TYPE_RSR;
|
||||
_assert_msg_(DYNA_REC, type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount");
|
||||
IndexOrShift = shift;
|
||||
Shift = type;
|
||||
Value = base;
|
||||
}
|
||||
|
||||
Operand2(ARMReg base, ShiftType type, u8 shift)// For IMM shifted register
|
||||
{
|
||||
if(shift == 32) shift = 0;
|
||||
switch (type)
|
||||
{
|
||||
case ST_LSL:
|
||||
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: LSL %u", shift);
|
||||
break;
|
||||
case ST_LSR:
|
||||
_assert_msg_(DYNA_REC, shift <= 32, "Invalid Operand2: LSR %u", shift);
|
||||
if (!shift)
|
||||
type = ST_LSL;
|
||||
if (shift == 32)
|
||||
shift = 0;
|
||||
break;
|
||||
case ST_ASR:
|
||||
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: LSR %u", shift);
|
||||
if (!shift)
|
||||
type = ST_LSL;
|
||||
if (shift == 32)
|
||||
shift = 0;
|
||||
break;
|
||||
case ST_ROR:
|
||||
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: ROR %u", shift);
|
||||
if (!shift)
|
||||
type = ST_LSL;
|
||||
break;
|
||||
case ST_RRX:
|
||||
_assert_msg_(DYNA_REC, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount");
|
||||
type = ST_ROR;
|
||||
break;
|
||||
}
|
||||
IndexOrShift = shift;
|
||||
Shift = type;
|
||||
Value = base;
|
||||
Type = TYPE_IMMSREG;
|
||||
}
|
||||
u32 GetData()
|
||||
{
|
||||
switch(Type)
|
||||
{
|
||||
case TYPE_IMM:
|
||||
return Imm12Mod(); // This'll need to be changed later
|
||||
case TYPE_REG:
|
||||
return Rm();
|
||||
case TYPE_IMMSREG:
|
||||
return IMMSR();
|
||||
case TYPE_RSR:
|
||||
return RSR();
|
||||
default:
|
||||
_assert_msg_(DYNA_REC, false, "GetData with Invalid Type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
u32 IMMSR() // IMM shifted register
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register");
|
||||
return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);
|
||||
}
|
||||
u32 RSR() // Register shifted register
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Type == TYPE_RSR, "RSR must be RSR Of Course");
|
||||
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;
|
||||
}
|
||||
u32 Rm()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Type == TYPE_REG, "Rm must be with Reg");
|
||||
return Value;
|
||||
}
|
||||
|
||||
u32 Imm5()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm5 not IMM value");
|
||||
return ((Value & 0x0000001F) << 7);
|
||||
}
|
||||
u32 Imm8()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value");
|
||||
return Value & 0xFF;
|
||||
}
|
||||
u32 Imm8Rot() // IMM8 with Rotation
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value");
|
||||
_assert_msg_(DYNA_REC, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);
|
||||
return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);
|
||||
}
|
||||
u32 Imm12()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12 not IMM");
|
||||
return (Value & 0x00000FFF);
|
||||
}
|
||||
|
||||
u32 Imm12Mod()
|
||||
{
|
||||
// This is a IMM12 with the top four bits being rotation and the
|
||||
// bottom eight being a IMM. This is for instructions that need to
|
||||
// expand a 8bit IMM to a 32bit value and gives you some rotation as
|
||||
// well.
|
||||
// Each rotation rotates to the right by 2 bits
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12Mod not IMM");
|
||||
return ((Rotation & 0xF) << 8) | (Value & 0xFF);
|
||||
}
|
||||
u32 Imm16()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
|
||||
return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);
|
||||
}
|
||||
u32 Imm16Low()
|
||||
{
|
||||
return Imm16();
|
||||
}
|
||||
u32 Imm16High() // Returns high 16bits
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
|
||||
return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);
|
||||
}
|
||||
u32 Imm24()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
|
||||
return (Value & 0x0FFFFFFF);
|
||||
}
|
||||
// NEON and ASIMD specific
|
||||
u32 Imm8ASIMD()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8ASIMD not IMM");
|
||||
return ((Value & 0x80) << 17) | ((Value & 0x70) << 12) | (Value & 0xF);
|
||||
}
|
||||
u32 Imm8VFP()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8VFP not IMM");
|
||||
return ((Value & 0xF0) << 12) | (Value & 0xF);
|
||||
}
|
||||
};
|
||||
|
||||
// Use these when you don't know if an imm can be represented as an operand2.
|
||||
// This lets you generate both an optimal and a fallback solution by checking
|
||||
// the return value, which will be false if these fail to find a Operand2 that
|
||||
// represents your 32-bit imm value.
|
||||
bool TryMakeOperand2(u32 imm, Operand2 &op2);
|
||||
bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);
|
||||
bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
|
||||
|
||||
// Use this only when you know imm can be made into an Operand2.
|
||||
Operand2 AssumeMakeOperand2(u32 imm);
|
||||
|
||||
inline Operand2 R(ARMReg Reg) { return Operand2(Reg, TYPE_REG); }
|
||||
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
|
||||
inline Operand2 Mem(void *ptr) { return Operand2((u32)ptr, TYPE_IMM); }
|
||||
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
|
||||
#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str)))
|
||||
|
||||
|
||||
struct FixupBranch
|
||||
{
|
||||
u8 *ptr;
|
||||
u32 condition; // Remembers our codition at the time
|
||||
int type; //0 = B 1 = BL
|
||||
};
|
||||
|
||||
struct LiteralPool
|
||||
{
|
||||
s32 loc;
|
||||
u8* ldr_address;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
typedef const u8* JumpTarget;
|
||||
|
||||
class ARMXEmitter
|
||||
{
|
||||
friend struct OpArg; // for Write8 etc
|
||||
private:
|
||||
u8 *code, *startcode;
|
||||
u8 *lastCacheFlushEnd;
|
||||
u32 condition;
|
||||
std::vector<LiteralPool> currentLitPool;
|
||||
|
||||
void WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 op2, bool RegAdd);
|
||||
void WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList);
|
||||
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2);
|
||||
|
||||
u32 EncodeVd(ARMReg Vd);
|
||||
u32 EncodeVn(ARMReg Vn);
|
||||
u32 EncodeVm(ARMReg Vm);
|
||||
void WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
|
||||
void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
|
||||
|
||||
// New Ops
|
||||
void WriteInstruction(u32 op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags = false);
|
||||
|
||||
protected:
|
||||
inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
|
||||
|
||||
public:
|
||||
ARMXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) {
|
||||
condition = CC_AL << 28;
|
||||
}
|
||||
ARMXEmitter(u8 *code_ptr) {
|
||||
code = code_ptr;
|
||||
lastCacheFlushEnd = code_ptr;
|
||||
startcode = code_ptr;
|
||||
condition = CC_AL << 28;
|
||||
}
|
||||
virtual ~ARMXEmitter() {}
|
||||
|
||||
void SetCodePtr(u8 *ptr);
|
||||
void ReserveCodeSpace(u32 bytes);
|
||||
const u8 *AlignCode16();
|
||||
const u8 *AlignCodePage();
|
||||
const u8 *GetCodePtr() const;
|
||||
void FlushIcache();
|
||||
void FlushIcacheSection(u8 *start, u8 *end);
|
||||
u8 *GetWritableCodePtr();
|
||||
|
||||
void FlushLitPool();
|
||||
void AddNewLit(u32 val);
|
||||
bool TrySetValue_TwoOp(ARMReg reg, u32 val);
|
||||
|
||||
CCFlags GetCC() { return CCFlags(condition >> 28); }
|
||||
void SetCC(CCFlags cond = CC_AL);
|
||||
|
||||
// Special purpose instructions
|
||||
|
||||
// Dynamic Endian Switching
|
||||
void SETEND(bool BE);
|
||||
// Debug Breakpoint
|
||||
void BKPT(u16 arg);
|
||||
|
||||
// Hint instruction
|
||||
void YIELD();
|
||||
|
||||
// Do nothing
|
||||
void NOP(int count = 1); //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)
|
||||
|
||||
#ifdef CALL
|
||||
#undef CALL
|
||||
#endif
|
||||
|
||||
// Branching
|
||||
FixupBranch B();
|
||||
FixupBranch B_CC(CCFlags Cond);
|
||||
void B_CC(CCFlags Cond, const void *fnptr);
|
||||
FixupBranch BL();
|
||||
FixupBranch BL_CC(CCFlags Cond);
|
||||
void SetJumpTarget(FixupBranch const &branch);
|
||||
|
||||
void B (const void *fnptr);
|
||||
void B (ARMReg src);
|
||||
void BL(const void *fnptr);
|
||||
void BL(ARMReg src);
|
||||
|
||||
void PUSH(const int num, ...);
|
||||
void POP(const int num, ...);
|
||||
|
||||
// New Data Ops
|
||||
void AND (ARMReg Rd, ARMReg Rn, Operand2 Rm);
|
||||
void ANDS(ARMReg Rd, ARMReg Rn, Operand2 Rm);
|
||||
void EOR (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void EORS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void SUB (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void SUBS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void RSB (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void RSBS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ADD (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ADDS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ADC (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ADCS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSL (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSL (ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void LSLS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSLS(ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void LSR (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void SBC (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void SBCS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void RBIT(ARMReg dest, ARMReg src);
|
||||
void REV (ARMReg dest, ARMReg src);
|
||||
void REV16 (ARMReg dest, ARMReg src);
|
||||
void RSC (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void RSCS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void TST ( ARMReg src, Operand2 op2);
|
||||
void TEQ ( ARMReg src, Operand2 op2);
|
||||
void CMP ( ARMReg src, Operand2 op2);
|
||||
void CMN ( ARMReg src, Operand2 op2);
|
||||
void ORR (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ORRS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void MOV (ARMReg dest, Operand2 op2);
|
||||
void MOVS(ARMReg dest, Operand2 op2);
|
||||
void BIC (ARMReg dest, ARMReg src, Operand2 op2); // BIC = ANDN
|
||||
void BICS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void MVN (ARMReg dest, Operand2 op2);
|
||||
void MVNS(ARMReg dest, Operand2 op2);
|
||||
void MOVW(ARMReg dest, Operand2 op2);
|
||||
void MOVT(ARMReg dest, Operand2 op2, bool TopBits = false);
|
||||
|
||||
// UDIV and SDIV are only available on CPUs that have
|
||||
// the idiva hardare capacity
|
||||
void UDIV(ARMReg dest, ARMReg dividend, ARMReg divisor);
|
||||
void SDIV(ARMReg dest, ARMReg dividend, ARMReg divisor);
|
||||
|
||||
void MUL (ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void MULS(ARMReg dest, ARMReg src, ARMReg op2);
|
||||
|
||||
void UMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
|
||||
void SMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
|
||||
|
||||
void UMLAL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
|
||||
void SMLAL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
|
||||
|
||||
void SXTB(ARMReg dest, ARMReg op2);
|
||||
void SXTH(ARMReg dest, ARMReg op2, u8 rotation = 0);
|
||||
void SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation = 0);
|
||||
void BFI(ARMReg rd, ARMReg rn, u8 lsb, u8 width);
|
||||
void UBFX(ARMReg dest, ARMReg op2, u8 lsb, u8 width);
|
||||
void CLZ(ARMReg rd, ARMReg rm);
|
||||
|
||||
// Using just MSR here messes with our defines on the PPC side of stuff (when this code was in dolphin...)
|
||||
// Just need to put an underscore here, bit annoying.
|
||||
void _MSR (bool nzcvq, bool g, Operand2 op2);
|
||||
void _MSR (bool nzcvq, bool g, ARMReg src);
|
||||
void MRS (ARMReg dest);
|
||||
|
||||
// Memory load/store operations
|
||||
void LDR (ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true);
|
||||
void LDRB (ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true);
|
||||
void LDRH (ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true);
|
||||
void LDRSB(ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true);
|
||||
void LDRSH(ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true);
|
||||
void STR (ARMReg result, ARMReg base, Operand2 op2 = 0, bool RegAdd = true);
|
||||
void STRB (ARMReg result, ARMReg base, Operand2 op2 = 0, bool RegAdd = true);
|
||||
void STRH (ARMReg result, ARMReg base, Operand2 op2 = 0, bool RegAdd = true);
|
||||
|
||||
void STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...);
|
||||
void LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...);
|
||||
|
||||
// Exclusive Access operations
|
||||
void LDREX(ARMReg dest, ARMReg base);
|
||||
// result contains the result if the instruction managed to store the value
|
||||
void STREX(ARMReg result, ARMReg base, ARMReg op);
|
||||
void DMB ();
|
||||
void SVC(Operand2 op);
|
||||
|
||||
// NEON and ASIMD instructions
|
||||
// None of these will be created with conditional since ARM
|
||||
// is deprecating conditional execution of ASIMD instructions.
|
||||
// ASIMD instructions don't even have a conditional encoding.
|
||||
|
||||
// Subtracts the base from the register to give us the real one
|
||||
ARMReg SubBase(ARMReg Reg);
|
||||
// NEON Only
|
||||
void VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
|
||||
// VFP Only
|
||||
void VLDR(ARMReg Dest, ARMReg Base, s16 offset);
|
||||
void VSTR(ARMReg Src, ARMReg Base, s16 offset);
|
||||
void VCMP(ARMReg Vd, ARMReg Vm);
|
||||
void VCMPE(ARMReg Vd, ARMReg Vm);
|
||||
// Compares against zero
|
||||
void VCMP(ARMReg Vd);
|
||||
void VCMPE(ARMReg Vd);
|
||||
|
||||
void VNMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VNMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VNMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VSQRT(ARMReg Vd, ARMReg Vm);
|
||||
|
||||
// NEON and VFP
|
||||
void VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VABS(ARMReg Vd, ARMReg Vm);
|
||||
void VNEG(ARMReg Vd, ARMReg Vm);
|
||||
void VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VMOV(ARMReg Dest, Operand2 op2);
|
||||
void VMOV(ARMReg Dest, ARMReg Src, bool high);
|
||||
void VMOV(ARMReg Dest, ARMReg Src);
|
||||
void VCVT(ARMReg Dest, ARMReg Src, int flags);
|
||||
|
||||
void VMRS_APSR();
|
||||
void VMRS(ARMReg Rt);
|
||||
void VMSR(ARMReg Rt);
|
||||
|
||||
void QuickCallFunction(ARMReg scratchreg, void *func);
|
||||
|
||||
// Wrapper around MOVT/MOVW with fallbacks.
|
||||
void MOVI2R(ARMReg reg, u32 val, bool optimize = true);
|
||||
void MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate = false);
|
||||
|
||||
void ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
||||
void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
||||
void CMPI2R(ARMReg rs, u32 val, ARMReg scratch);
|
||||
void ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
||||
|
||||
|
||||
}; // class ARMXEmitter
|
||||
|
||||
|
||||
// Everything that needs to generate X86 code should inherit from this.
|
||||
// You get memory management for free, plus, you can use all the MOV etc functions without
|
||||
// having to prefix them with gen-> or something similar.
|
||||
class ARMXCodeBlock : public ARMXEmitter
|
||||
{
|
||||
protected:
|
||||
u8 *region;
|
||||
size_t region_size;
|
||||
|
||||
public:
|
||||
ARMXCodeBlock() : region(NULL), region_size(0) {}
|
||||
virtual ~ARMXCodeBlock() { if (region) FreeCodeSpace(); }
|
||||
|
||||
// Call this before you generate any code.
|
||||
void AllocCodeSpace(int size)
|
||||
{
|
||||
region_size = size;
|
||||
region = (u8*)AllocateExecutableMemory(region_size);
|
||||
SetCodePtr(region);
|
||||
}
|
||||
|
||||
// Always clear code space with breakpoints, so that if someone accidentally executes
|
||||
// uninitialized, it just breaks into the debugger.
|
||||
void ClearCodeSpace()
|
||||
{
|
||||
// x86/64: 0xCC = breakpoint
|
||||
memset(region, 0xCC, region_size);
|
||||
ResetCodePtr();
|
||||
}
|
||||
|
||||
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
|
||||
void FreeCodeSpace()
|
||||
{
|
||||
#ifndef __SYMBIAN32__
|
||||
FreeMemoryPages(region, region_size);
|
||||
#endif
|
||||
region = NULL;
|
||||
region_size = 0;
|
||||
}
|
||||
|
||||
bool IsInSpace(u8 *ptr)
|
||||
{
|
||||
return ptr >= region && ptr < region + region_size;
|
||||
}
|
||||
|
||||
// Cannot currently be undone. Will write protect the entire code region.
|
||||
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
|
||||
void WriteProtect()
|
||||
{
|
||||
WriteProtectMemory(region, region_size, true);
|
||||
}
|
||||
void UnWriteProtect()
|
||||
{
|
||||
UnWriteProtectMemory(region, region_size, false);
|
||||
}
|
||||
|
||||
void ResetCodePtr()
|
||||
{
|
||||
SetCodePtr(region);
|
||||
}
|
||||
|
||||
size_t GetSpaceLeft() const
|
||||
{
|
||||
return region_size - (GetCodePtr() - region);
|
||||
}
|
||||
|
||||
u8 *GetBasePtr() {
|
||||
return region;
|
||||
}
|
||||
|
||||
size_t GetOffset(u8 *ptr) {
|
||||
return ptr - region;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // _DOLPHIN_INTEL_CODEGEN_
|
|
@ -0,0 +1,57 @@
|
|||
// 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 <map>
|
||||
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "Thunk.h"
|
||||
|
||||
#define THUNK_ARENA_SIZE 1024*1024*1
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static u8 GC_ALIGNED32(saved_fp_state[16 * 4 * 4]);
|
||||
static u8 GC_ALIGNED32(saved_gpr_state[16 * 8]);
|
||||
static u16 saved_mxcsr;
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace ArmGen;
|
||||
|
||||
void ThunkManager::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void ThunkManager::Reset()
|
||||
{
|
||||
thunks.clear();
|
||||
ResetCodePtr();
|
||||
}
|
||||
|
||||
void ThunkManager::Shutdown()
|
||||
{
|
||||
Reset();
|
||||
FreeCodeSpace();
|
||||
}
|
||||
|
||||
void *ThunkManager::ProtectFunction(void *function, int num_params)
|
||||
{
|
||||
_dbg_assert_msg_(JIT, false, "Arm ThunkManager not implemented? Will crash.");
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _ATOMIC_GCC_H_
|
||||
#define _ATOMIC_GCC_H_
|
||||
|
||||
#ifdef BLACKBERRY
|
||||
#include <atomic.h>
|
||||
#elif defined(__SYMBIAN32__)
|
||||
#include <glib/gatomic.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
// Atomic operations are performed in a single step by the CPU. It is
|
||||
// impossible for other threads to see the operation "half-done."
|
||||
//
|
||||
// Some atomic operations can be combined with different types of memory
|
||||
// barriers called "Acquire semantics" and "Release semantics", defined below.
|
||||
//
|
||||
// Acquire semantics: Future memory accesses cannot be relocated to before the
|
||||
// operation.
|
||||
//
|
||||
// Release semantics: Past memory accesses cannot be relocated to after the
|
||||
// operation.
|
||||
//
|
||||
// These barriers affect not only the compiler, but also the CPU.
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
||||
inline void AtomicAdd(volatile u32& target, u32 value) {
|
||||
__sync_add_and_fetch(&target, value);
|
||||
}
|
||||
|
||||
inline void AtomicAnd(volatile u32& target, u32 value) {
|
||||
__sync_and_and_fetch(&target, value);
|
||||
}
|
||||
|
||||
inline void AtomicDecrement(volatile u32& target) {
|
||||
__sync_add_and_fetch(&target, -1);
|
||||
}
|
||||
|
||||
inline void AtomicIncrement(volatile u32& target) {
|
||||
__sync_add_and_fetch(&target, 1);
|
||||
}
|
||||
|
||||
inline u32 AtomicLoad(volatile u32& src) {
|
||||
return src; // 32-bit reads are always atomic.
|
||||
}
|
||||
inline u32 AtomicLoadAcquire(volatile u32& src) {
|
||||
//keep the compiler from caching any memory references
|
||||
u32 result = src; // 32-bit reads are always atomic.
|
||||
//__sync_synchronize(); // TODO: May not be necessary.
|
||||
// Compiler instruction only. x86 loads always have acquire semantics.
|
||||
__asm__ __volatile__ ( "":::"memory" );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void AtomicOr(volatile u32& target, u32 value) {
|
||||
__sync_or_and_fetch(&target, value);
|
||||
}
|
||||
|
||||
inline void AtomicStore(volatile u32& dest, u32 value) {
|
||||
dest = value; // 32-bit writes are always atomic.
|
||||
}
|
||||
inline void AtomicStoreRelease(volatile u32& dest, u32 value) {
|
||||
#ifdef BLACKBERRY
|
||||
atomic_set(&dest, value);
|
||||
#elif defined(__SYMBIAN32__)
|
||||
g_atomic_int_set(&dest, value);
|
||||
#else
|
||||
__sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics.
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Old code kept here for reference in case we need the parts with __asm__ __volatile__.
|
||||
#if 0
|
||||
LONG SyncInterlockedIncrement(LONG *Dest)
|
||||
{
|
||||
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
||||
return __sync_add_and_fetch(Dest, 1);
|
||||
#else
|
||||
register int result;
|
||||
__asm__ __volatile__("lock; xadd %0,%1"
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (1), "m" (*Dest)
|
||||
: "memory");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
|
||||
{
|
||||
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
||||
return __sync_add_and_fetch(Dest, Val);
|
||||
#else
|
||||
register int result;
|
||||
__asm__ __volatile__("lock; xadd %0,%1"
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (Val), "m" (*Dest)
|
||||
: "memory");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
|
||||
{
|
||||
#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
|
||||
return __sync_lock_test_and_set(Dest, Val);
|
||||
#else
|
||||
register int result;
|
||||
__asm__ __volatile__("lock; xchg %0,%1"
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (Val), "m" (*Dest)
|
||||
: "memory");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,85 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _ATOMIC_WIN32_H_
|
||||
#define _ATOMIC_WIN32_H_
|
||||
|
||||
#include "Common.h"
|
||||
#include <intrin.h>
|
||||
#include <Windows.h>
|
||||
|
||||
// Atomic operations are performed in a single step by the CPU. It is
|
||||
// impossible for other threads to see the operation "half-done."
|
||||
//
|
||||
// Some atomic operations can be combined with different types of memory
|
||||
// barriers called "Acquire semantics" and "Release semantics", defined below.
|
||||
//
|
||||
// Acquire semantics: Future memory accesses cannot be relocated to before the
|
||||
// operation.
|
||||
//
|
||||
// Release semantics: Past memory accesses cannot be relocated to after the
|
||||
// operation.
|
||||
//
|
||||
// These barriers affect not only the compiler, but also the CPU.
|
||||
//
|
||||
// NOTE: Acquire and Release are not differentiated right now. They perform a
|
||||
// full memory barrier instead of a "one-way" memory barrier. The newest
|
||||
// Windows SDK has Acquire and Release versions of some Interlocked* functions.
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
||||
inline void AtomicAdd(volatile u32& target, u32 value) {
|
||||
InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value);
|
||||
}
|
||||
|
||||
inline void AtomicAnd(volatile u32& target, u32 value) {
|
||||
_InterlockedAnd((volatile LONG*)&target, (LONG)value);
|
||||
}
|
||||
|
||||
inline void AtomicIncrement(volatile u32& target) {
|
||||
InterlockedIncrement((volatile LONG*)&target);
|
||||
}
|
||||
|
||||
inline void AtomicDecrement(volatile u32& target) {
|
||||
InterlockedDecrement((volatile LONG*)&target);
|
||||
}
|
||||
|
||||
inline u32 AtomicLoad(volatile u32& src) {
|
||||
return src; // 32-bit reads are always atomic.
|
||||
}
|
||||
inline u32 AtomicLoadAcquire(volatile u32& src) {
|
||||
u32 result = src; // 32-bit reads are always atomic.
|
||||
_ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics.
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void AtomicOr(volatile u32& target, u32 value) {
|
||||
_InterlockedOr((volatile LONG*)&target, (LONG)value);
|
||||
}
|
||||
|
||||
inline void AtomicStore(volatile u32& dest, u32 value) {
|
||||
dest = value; // 32-bit writes are always atomic.
|
||||
}
|
||||
inline void AtomicStoreRelease(volatile u32& dest, u32 value) {
|
||||
_WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics.
|
||||
dest = value; // 32-bit writes are always atomic.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _ATOMIC_H_
|
||||
#define _ATOMIC_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "Atomic_Win32.h"
|
||||
|
||||
#else
|
||||
|
||||
// GCC-compatible compiler assumed!
|
||||
#include "Atomic_GCC.h"
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
set(SRCS
|
||||
ColorUtil.cpp
|
||||
ConsoleListener.cpp
|
||||
ExtendedTrace.cpp
|
||||
#FPURoundModeX86.cpp
|
||||
FileSearch.cpp
|
||||
FileUtil.cpp
|
||||
Hash.cpp
|
||||
IniFile.cpp
|
||||
LogManager.cpp
|
||||
MemArena.cpp
|
||||
MemoryUtil.cpp
|
||||
Misc.cpp
|
||||
MsgHandler.cpp
|
||||
StringUtils.cpp
|
||||
Thread.cpp
|
||||
ThreadPools.cpp
|
||||
Timer.cpp
|
||||
)
|
||||
|
||||
# TODO
|
||||
if (ARM)
|
||||
set(SRCS ${SRCS} ArmEmitter.cpp ArmABI.cpp)
|
||||
else()
|
||||
set(SRCS ${SRCS} CPUDetect.cpp MathUtil.cpp Thunk.cpp x64Analyzer.cpp x64Emitter.cpp ABI.cpp)
|
||||
endif (ARM)
|
||||
|
||||
set(SRCS ${SRCS})
|
||||
|
||||
add_library(common STATIC ${SRCS})
|
||||
|
||||
if(UNIX)
|
||||
add_definitions(-fPIC)
|
||||
endif(UNIX)
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
// 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 <memory.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
|
||||
#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
|
||||
#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
|
||||
#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
|
||||
#include <intrin.h>
|
||||
#undef _interlockedbittestandset
|
||||
#undef _interlockedbittestandreset
|
||||
#undef _interlockedbittestandset64
|
||||
#undef _interlockedbittestandreset64
|
||||
#else
|
||||
|
||||
#if !defined(_M_GENERIC) && !defined(MIPS)
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#if defined __FreeBSD__
|
||||
#include <sys/types.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#elif !defined(MIPS)
|
||||
void __cpuid(int regs[4], int cpuid_leaf)
|
||||
{
|
||||
int eax, ebx, ecx, edx;
|
||||
asm volatile (
|
||||
#if defined(__i386__)
|
||||
"pushl %%ebx;\n\t"
|
||||
#endif
|
||||
"movl %4, %%eax;\n\t"
|
||||
"cpuid;\n\t"
|
||||
"movl %%eax, %0;\n\t"
|
||||
"movl %%ebx, %1;\n\t"
|
||||
"movl %%ecx, %2;\n\t"
|
||||
"movl %%edx, %3;\n\t"
|
||||
#if defined(__i386__)
|
||||
"popl %%ebx;\n\t"
|
||||
#endif
|
||||
:"=m" (eax), "=m" (ebx), "=m" (ecx), "=m" (edx)
|
||||
:"r" (cpuid_leaf)
|
||||
:"%eax",
|
||||
#if !defined(__i386__)
|
||||
"%ebx",
|
||||
#endif
|
||||
"%ecx", "%edx");
|
||||
|
||||
regs[0] = eax;
|
||||
regs[1] = ebx;
|
||||
regs[2] = ecx;
|
||||
regs[3] = edx;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "CPUDetect.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
CPUInfo cpu_info;
|
||||
|
||||
CPUInfo::CPUInfo() {
|
||||
Detect();
|
||||
}
|
||||
|
||||
// Detects the various cpu features
|
||||
void CPUInfo::Detect()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
#ifdef _M_IX86
|
||||
Mode64bit = false;
|
||||
#elif defined (_M_X64)
|
||||
Mode64bit = true;
|
||||
OS64bit = true;
|
||||
#endif
|
||||
num_cores = 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _M_IX86
|
||||
BOOL f64 = false;
|
||||
IsWow64Process(GetCurrentProcess(), &f64);
|
||||
OS64bit = (f64 == TRUE) ? true : false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set obvious defaults, for extra safety
|
||||
if (Mode64bit) {
|
||||
bSSE = true;
|
||||
bSSE2 = true;
|
||||
bLongMode = true;
|
||||
}
|
||||
|
||||
// Assume CPU supports the CPUID instruction. Those that don't can barely
|
||||
// boot modern OS:es anyway.
|
||||
int cpu_id[4];
|
||||
memset(cpu_string, 0, sizeof(cpu_string));
|
||||
|
||||
// Detect CPU's CPUID capabilities, and grab cpu string
|
||||
__cpuid(cpu_id, 0x00000000);
|
||||
u32 max_std_fn = cpu_id[0]; // EAX
|
||||
*((int *)cpu_string) = cpu_id[1];
|
||||
*((int *)(cpu_string + 4)) = cpu_id[3];
|
||||
*((int *)(cpu_string + 8)) = cpu_id[2];
|
||||
__cpuid(cpu_id, 0x80000000);
|
||||
u32 max_ex_fn = cpu_id[0];
|
||||
if (!strcmp(cpu_string, "GenuineIntel"))
|
||||
vendor = VENDOR_INTEL;
|
||||
else if (!strcmp(cpu_string, "AuthenticAMD"))
|
||||
vendor = VENDOR_AMD;
|
||||
else
|
||||
vendor = VENDOR_OTHER;
|
||||
|
||||
// Set reasonable default brand string even if brand string not available.
|
||||
strcpy(brand_string, cpu_string);
|
||||
|
||||
// Detect family and other misc stuff.
|
||||
bool ht = false;
|
||||
HTT = ht;
|
||||
logical_cpu_count = 1;
|
||||
if (max_std_fn >= 1) {
|
||||
__cpuid(cpu_id, 0x00000001);
|
||||
logical_cpu_count = (cpu_id[1] >> 16) & 0xFF;
|
||||
ht = (cpu_id[3] >> 28) & 1;
|
||||
|
||||
if ((cpu_id[3] >> 25) & 1) bSSE = true;
|
||||
if ((cpu_id[3] >> 26) & 1) bSSE2 = true;
|
||||
if ((cpu_id[2]) & 1) bSSE3 = true;
|
||||
if ((cpu_id[2] >> 9) & 1) bSSSE3 = true;
|
||||
if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true;
|
||||
if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
|
||||
if ((cpu_id[2] >> 28) & 1) bAVX = true;
|
||||
if ((cpu_id[2] >> 25) & 1) bAES = true;
|
||||
}
|
||||
if (max_ex_fn >= 0x80000004) {
|
||||
// Extract brand string
|
||||
__cpuid(cpu_id, 0x80000002);
|
||||
memcpy(brand_string, cpu_id, sizeof(cpu_id));
|
||||
__cpuid(cpu_id, 0x80000003);
|
||||
memcpy(brand_string + 16, cpu_id, sizeof(cpu_id));
|
||||
__cpuid(cpu_id, 0x80000004);
|
||||
memcpy(brand_string + 32, cpu_id, sizeof(cpu_id));
|
||||
}
|
||||
if (max_ex_fn >= 0x80000001) {
|
||||
// Check for more features.
|
||||
__cpuid(cpu_id, 0x80000001);
|
||||
bool cmp_legacy = false;
|
||||
if (cpu_id[2] & 1) bLAHFSAHF64 = true;
|
||||
if (cpu_id[2] & 2) cmp_legacy = true; //wtf is this?
|
||||
if ((cpu_id[3] >> 29) & 1) bLongMode = true;
|
||||
}
|
||||
|
||||
num_cores = (logical_cpu_count == 0) ? 1 : logical_cpu_count;
|
||||
|
||||
if (max_ex_fn >= 0x80000008) {
|
||||
// Get number of cores. This is a bit complicated. Following AMD manual here.
|
||||
__cpuid(cpu_id, 0x80000008);
|
||||
int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF;
|
||||
if (apic_id_core_id_size == 0) {
|
||||
if (ht) {
|
||||
// New mechanism for modern Intel CPUs.
|
||||
if (vendor == VENDOR_INTEL) {
|
||||
__cpuid(cpu_id, 0x00000004);
|
||||
int cores_x_package = ((cpu_id[0] >> 26) & 0x3F) + 1;
|
||||
HTT = (cores_x_package < logical_cpu_count);
|
||||
cores_x_package = ((logical_cpu_count % cores_x_package) == 0) ? cores_x_package : 1;
|
||||
num_cores = (cores_x_package > 1) ? cores_x_package : num_cores;
|
||||
logical_cpu_count /= cores_x_package;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Use AMD's new method.
|
||||
num_cores = (cpu_id[2] & 0xFF) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn the cpu info into a string we can show
|
||||
std::string CPUInfo::Summarize()
|
||||
{
|
||||
std::string sum;
|
||||
if (num_cores == 1)
|
||||
sum = StringFromFormat("%s, %i core", cpu_string, num_cores);
|
||||
else
|
||||
{
|
||||
sum = StringFromFormat("%s, %i cores", cpu_string, num_cores);
|
||||
if (HTT) sum += StringFromFormat(" (%i logical threads per physical core)", logical_cpu_count);
|
||||
}
|
||||
if (bSSE) sum += ", SSE";
|
||||
if (bSSE2) sum += ", SSE2";
|
||||
if (bSSE3) sum += ", SSE3";
|
||||
if (bSSSE3) sum += ", SSSE3";
|
||||
if (bSSE4_1) sum += ", SSE4.1";
|
||||
if (bSSE4_2) sum += ", SSE4.2";
|
||||
if (HTT) sum += ", HTT";
|
||||
if (bAVX) sum += ", AVX";
|
||||
if (bAES) sum += ", AES";
|
||||
if (bLongMode) sum += ", 64-bit support";
|
||||
return sum;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// 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/
|
||||
|
||||
// Detect the cpu, so we'll know which optimizations to use
|
||||
#ifndef _CPUDETECT_H_
|
||||
#define _CPUDETECT_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
enum CPUVendor
|
||||
{
|
||||
VENDOR_INTEL = 0,
|
||||
VENDOR_AMD = 1,
|
||||
VENDOR_ARM = 2,
|
||||
VENDOR_OTHER = 3,
|
||||
};
|
||||
|
||||
struct CPUInfo
|
||||
{
|
||||
CPUVendor vendor;
|
||||
|
||||
char cpu_string[0x21];
|
||||
char brand_string[0x41];
|
||||
bool OS64bit;
|
||||
bool CPU64bit;
|
||||
bool Mode64bit;
|
||||
|
||||
bool HTT;
|
||||
int num_cores;
|
||||
int logical_cpu_count;
|
||||
|
||||
bool bSSE;
|
||||
bool bSSE2;
|
||||
bool bSSE3;
|
||||
bool bSSSE3;
|
||||
bool bPOPCNT;
|
||||
bool bSSE4_1;
|
||||
bool bSSE4_2;
|
||||
bool bLZCNT;
|
||||
bool bSSE4A;
|
||||
bool bAVX;
|
||||
bool bAES;
|
||||
bool bLAHFSAHF64;
|
||||
bool bLongMode;
|
||||
|
||||
// ARM specific CPUInfo
|
||||
bool bSwp;
|
||||
bool bHalf;
|
||||
bool bThumb;
|
||||
bool bFastMult;
|
||||
bool bVFP;
|
||||
bool bEDSP;
|
||||
bool bThumbEE;
|
||||
bool bNEON;
|
||||
bool bVFPv3;
|
||||
bool bTLS;
|
||||
bool bVFPv4;
|
||||
bool bIDIVa;
|
||||
bool bIDIVt;
|
||||
bool bArmV7; // enable MOVT, MOVW etc
|
||||
|
||||
// ARMv8 specific
|
||||
bool bFP;
|
||||
bool bASIMD;
|
||||
|
||||
// Call Detect()
|
||||
explicit CPUInfo();
|
||||
|
||||
// Turn the cpu info into a string we can show
|
||||
std::string Summarize();
|
||||
|
||||
private:
|
||||
// Detects the various cpu features
|
||||
void Detect();
|
||||
};
|
||||
|
||||
extern CPUInfo cpu_info;
|
||||
|
||||
#endif // _CPUDETECT_H_
|
|
@ -0,0 +1,773 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _POINTERWRAP_H_
|
||||
#define _POINTERWRAP_H_
|
||||
|
||||
// Extremely simple serialization framework.
|
||||
|
||||
// (mis)-features:
|
||||
// + Super fast
|
||||
// + Very simple
|
||||
// + Same code is used for serialization and deserializaition (in most cases)
|
||||
// - Zero backwards/forwards compatibility
|
||||
// - Serialization code for anything complex has to be manually written.
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#ifndef __SYMBIAN32__
|
||||
#if defined(IOS) || defined(MACGNUSTD)
|
||||
#include <tr1/type_traits>
|
||||
#else
|
||||
#include <type_traits>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
#include "../ext/snappy/snappy-c.h"
|
||||
|
||||
#if defined(IOS) || defined(MACGNUSTD)
|
||||
namespace std {
|
||||
using tr1::is_pointer;
|
||||
}
|
||||
#endif
|
||||
#ifdef __SYMBIAN32__
|
||||
namespace std {
|
||||
template <bool bool_value>
|
||||
struct bool_constant {
|
||||
typedef bool_constant<bool_value> type;
|
||||
static const bool value = bool_value;
|
||||
};
|
||||
template <bool bool_value> const bool bool_constant<bool_value>::value;
|
||||
template <typename T> struct is_pointer : public bool_constant<false> {};
|
||||
template <typename T> struct is_pointer<T*> : public bool_constant<true> {};
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
struct LinkedListItem : public T
|
||||
{
|
||||
LinkedListItem<T> *next;
|
||||
};
|
||||
|
||||
// Wrapper class
|
||||
class PointerWrap
|
||||
{
|
||||
// This makes it a compile error if you forget to define DoState() on non-POD.
|
||||
// Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
|
||||
#ifdef _MSC_VER
|
||||
template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value>
|
||||
#else
|
||||
template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
|
||||
#endif
|
||||
struct DoHelper
|
||||
{
|
||||
static void DoArray(PointerWrap *p, T *x, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
p->Do(x[i]);
|
||||
}
|
||||
|
||||
static void Do(PointerWrap *p, T &x)
|
||||
{
|
||||
p->DoClass(x);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DoHelper<T, true, false>
|
||||
{
|
||||
static void DoArray(PointerWrap *p, T *x, int count)
|
||||
{
|
||||
p->DoVoid((void *)x, sizeof(T) * count);
|
||||
}
|
||||
|
||||
static void Do(PointerWrap *p, T &x)
|
||||
{
|
||||
p->DoVoid((void *)&x, sizeof(x));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
MODE_READ = 1, // load
|
||||
MODE_WRITE, // save
|
||||
MODE_MEASURE, // calculate size
|
||||
MODE_VERIFY, // compare
|
||||
};
|
||||
|
||||
enum Error {
|
||||
ERROR_NONE = 0,
|
||||
ERROR_WARNING = 1,
|
||||
ERROR_FAILURE = 2,
|
||||
};
|
||||
|
||||
u8 **ptr;
|
||||
Mode mode;
|
||||
Error error;
|
||||
|
||||
public:
|
||||
PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {}
|
||||
PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {}
|
||||
|
||||
void SetMode(Mode mode_) {mode = mode_;}
|
||||
Mode GetMode() const {return mode;}
|
||||
u8 **GetPPtr() {return ptr;}
|
||||
void SetError(Error error_)
|
||||
{
|
||||
if (error < error_)
|
||||
error = error_;
|
||||
if (error > ERROR_WARNING)
|
||||
mode = PointerWrap::MODE_MEASURE;
|
||||
}
|
||||
|
||||
void DoVoid(void *data, int size)
|
||||
{
|
||||
switch (mode) {
|
||||
case MODE_READ: memcpy(data, *ptr, size); break;
|
||||
case MODE_WRITE: memcpy(*ptr, data, size); break;
|
||||
case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
|
||||
case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break;
|
||||
default: break; // throw an error?
|
||||
}
|
||||
(*ptr) += size;
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void Do(std::map<K, T *> &x)
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second != NULL)
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
T *dv = NULL;
|
||||
DoMap(x, dv);
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void Do(std::map<K, T> &x)
|
||||
{
|
||||
T dv;
|
||||
DoMap(x, dv);
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void DoMap(std::map<K, T> &x, T &default_val)
|
||||
{
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
{
|
||||
x.clear();
|
||||
while (number > 0)
|
||||
{
|
||||
K first = 0;
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
x[first] = second;
|
||||
--number;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY:
|
||||
{
|
||||
typename std::map<K, T>::iterator itr = x.begin();
|
||||
while (number > 0)
|
||||
{
|
||||
Do(itr->first);
|
||||
Do(itr->second);
|
||||
--number;
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void Do(std::multimap<K, T *> &x)
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second != NULL)
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
T *dv = NULL;
|
||||
DoMultimap(x, dv);
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void Do(std::multimap<K, T> &x)
|
||||
{
|
||||
T dv;
|
||||
DoMultimap(x, dv);
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void DoMultimap(std::multimap<K, T> &x, T &default_val)
|
||||
{
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
{
|
||||
x.clear();
|
||||
while (number > 0)
|
||||
{
|
||||
K first;
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
x.insert(std::make_pair(first, second));
|
||||
--number;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY:
|
||||
{
|
||||
typename std::multimap<K, T>::iterator itr = x.begin();
|
||||
while (number > 0)
|
||||
{
|
||||
Do(itr->first);
|
||||
Do(itr->second);
|
||||
--number;
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Store vectors.
|
||||
template<class T>
|
||||
void Do(std::vector<T *> &x)
|
||||
{
|
||||
T *dv = NULL;
|
||||
DoVector(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::vector<T> &x)
|
||||
{
|
||||
T dv;
|
||||
DoVector(x, dv);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void DoPOD(std::vector<T> &x)
|
||||
{
|
||||
T dv;
|
||||
DoVectorPOD(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::vector<T> &x, T &default_val)
|
||||
{
|
||||
DoVector(x, default_val);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoVector(std::vector<T> &x, T &default_val)
|
||||
{
|
||||
u32 vec_size = (u32)x.size();
|
||||
Do(vec_size);
|
||||
x.resize(vec_size, default_val);
|
||||
if (vec_size > 0)
|
||||
DoArray(&x[0], vec_size);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoVectorPOD(std::vector<T> &x, T &default_val)
|
||||
{
|
||||
u32 vec_size = (u32)x.size();
|
||||
Do(vec_size);
|
||||
x.resize(vec_size, default_val);
|
||||
if (vec_size > 0)
|
||||
DoArray(&x[0], vec_size);
|
||||
}
|
||||
|
||||
// Store deques.
|
||||
template<class T>
|
||||
void Do(std::deque<T *> &x)
|
||||
{
|
||||
T *dv = NULL;
|
||||
DoDeque(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::deque<T> &x)
|
||||
{
|
||||
T dv;
|
||||
DoDeque(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoDeque(std::deque<T> &x, T &default_val)
|
||||
{
|
||||
u32 deq_size = (u32)x.size();
|
||||
Do(deq_size);
|
||||
x.resize(deq_size, default_val);
|
||||
u32 i;
|
||||
for(i = 0; i < deq_size; i++)
|
||||
Do(x[i]);
|
||||
}
|
||||
|
||||
// Store STL lists.
|
||||
template<class T>
|
||||
void Do(std::list<T *> &x)
|
||||
{
|
||||
T *dv = NULL;
|
||||
Do(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::list<T> &x)
|
||||
{
|
||||
T dv;
|
||||
DoList(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::list<T> &x, T &default_val)
|
||||
{
|
||||
DoList(x, default_val);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoList(std::list<T> &x, T &default_val)
|
||||
{
|
||||
u32 list_size = (u32)x.size();
|
||||
Do(list_size);
|
||||
x.resize(list_size, default_val);
|
||||
|
||||
typename std::list<T>::iterator itr, end;
|
||||
for (itr = x.begin(), end = x.end(); itr != end; ++itr)
|
||||
Do(*itr);
|
||||
}
|
||||
|
||||
|
||||
// Store STL sets.
|
||||
template <class T>
|
||||
void Do(std::set<T *> &x)
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||
{
|
||||
if (*it != NULL)
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
DoSet(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Do(std::set<T> &x)
|
||||
{
|
||||
DoSet(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoSet(std::set<T> &x)
|
||||
{
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case MODE_READ:
|
||||
{
|
||||
x.clear();
|
||||
while (number-- > 0)
|
||||
{
|
||||
T it;
|
||||
Do(it);
|
||||
x.insert(it);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY:
|
||||
{
|
||||
typename std::set<T>::iterator itr = x.begin();
|
||||
while (number-- > 0)
|
||||
Do(*itr++);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode);
|
||||
}
|
||||
}
|
||||
|
||||
// Store strings.
|
||||
void Do(std::string &x)
|
||||
{
|
||||
int stringLen = (int)x.length() + 1;
|
||||
Do(stringLen);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ: x = (char*)*ptr; break;
|
||||
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
|
||||
case MODE_MEASURE: break;
|
||||
case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break;
|
||||
}
|
||||
(*ptr) += stringLen;
|
||||
}
|
||||
|
||||
void Do(std::wstring &x)
|
||||
{
|
||||
int stringLen = sizeof(wchar_t)*((int)x.length() + 1);
|
||||
Do(stringLen);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ: x = (wchar_t*)*ptr; break;
|
||||
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
|
||||
case MODE_MEASURE: break;
|
||||
case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
|
||||
}
|
||||
(*ptr) += stringLen;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoClass(T &x) {
|
||||
x.DoState(*this);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoClass(T *&x) {
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
if (x != NULL)
|
||||
delete x;
|
||||
x = new T();
|
||||
}
|
||||
x->DoState(*this);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoArray(T *x, int count) {
|
||||
DoHelper<T>::DoArray(this, x, count);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(T &x) {
|
||||
DoHelper<T>::Do(this, x);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoPOD(T &x) {
|
||||
DoHelper<T>::Do(this, x);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoPointer(T* &x, T*const base) {
|
||||
// pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range
|
||||
s32 offset = x - base;
|
||||
Do(offset);
|
||||
if (mode == MODE_READ)
|
||||
x = base + offset;
|
||||
}
|
||||
|
||||
template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)>
|
||||
void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end=0)
|
||||
{
|
||||
LinkedListItem<T>* list_cur = list_start;
|
||||
LinkedListItem<T>* prev = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
u8 shouldExist = (list_cur ? 1 : 0);
|
||||
Do(shouldExist);
|
||||
if (shouldExist == 1)
|
||||
{
|
||||
LinkedListItem<T>* cur = list_cur ? list_cur : TNew();
|
||||
TDo(*this, (T*)cur);
|
||||
if (!list_cur)
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
cur->next = 0;
|
||||
list_cur = cur;
|
||||
if (prev)
|
||||
prev->next = cur;
|
||||
else
|
||||
list_start = cur;
|
||||
}
|
||||
else
|
||||
{
|
||||
TFree(cur);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
if (prev)
|
||||
prev->next = 0;
|
||||
if (list_end)
|
||||
*list_end = prev;
|
||||
if (list_cur)
|
||||
{
|
||||
if (list_start == list_cur)
|
||||
list_start = 0;
|
||||
do
|
||||
{
|
||||
LinkedListItem<T>* next = list_cur->next;
|
||||
TFree(list_cur);
|
||||
list_cur = next;
|
||||
}
|
||||
while (list_cur);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = list_cur;
|
||||
list_cur = list_cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
void DoMarker(const char* prevName, u32 arbitraryNumber=0x42)
|
||||
{
|
||||
u32 cookie = arbitraryNumber;
|
||||
Do(cookie);
|
||||
if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber)
|
||||
{
|
||||
PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
|
||||
SetError(ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CChunkFileReader
|
||||
{
|
||||
public:
|
||||
// Load file template
|
||||
template<class T>
|
||||
static bool Load(const std::string& _rFilename, int _Revision, T& _class, std::string* _failureReason)
|
||||
{
|
||||
INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str());
|
||||
_failureReason->clear();
|
||||
_failureReason->append("LoadStateWrongVersion");
|
||||
|
||||
if (!File::Exists(_rFilename)) {
|
||||
_failureReason->clear();
|
||||
_failureReason->append("LoadStateDoesntExist");
|
||||
ERROR_LOG(COMMON, "ChunkReader: File doesn't exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check file size
|
||||
const u64 fileSize = File::GetSize(_rFilename);
|
||||
static const u64 headerSize = sizeof(SChunkHeader);
|
||||
if (fileSize < headerSize)
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: File too small");
|
||||
return false;
|
||||
}
|
||||
|
||||
File::IOFile pFile(_rFilename, "rb");
|
||||
if (!pFile)
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading");
|
||||
return false;
|
||||
}
|
||||
|
||||
// read the header
|
||||
SChunkHeader header;
|
||||
if (!pFile.ReadArray(&header, 1))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Bad header size");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check revision
|
||||
if (header.Revision != _Revision)
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d",
|
||||
header.Revision, _Revision);
|
||||
return false;
|
||||
}
|
||||
|
||||
// get size
|
||||
const int sz = (int)(fileSize - headerSize);
|
||||
if (header.ExpectedSize != sz)
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d",
|
||||
sz, header.ExpectedSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
// read the state
|
||||
u8* buffer = new u8[sz];
|
||||
if (!pFile.ReadBytes(buffer, sz))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Error reading file");
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 *ptr = buffer;
|
||||
u8 *buf = buffer;
|
||||
if (header.Compress) {
|
||||
u8 *uncomp_buffer = new u8[header.UncompressedSize];
|
||||
size_t uncomp_size = header.UncompressedSize;
|
||||
snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size);
|
||||
if ((int)uncomp_size != header.UncompressedSize) {
|
||||
ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size);
|
||||
}
|
||||
ptr = uncomp_buffer;
|
||||
buf = uncomp_buffer;
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
PointerWrap p(&ptr, PointerWrap::MODE_READ);
|
||||
_class.DoState(p);
|
||||
delete[] buf;
|
||||
|
||||
INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str());
|
||||
return p.error != p.ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Save file template
|
||||
template<class T>
|
||||
static bool Save(const std::string& _rFilename, int _Revision, T& _class)
|
||||
{
|
||||
INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str());
|
||||
|
||||
File::IOFile pFile(_rFilename, "wb");
|
||||
if (!pFile)
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Error opening file for write");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compress = true;
|
||||
|
||||
// Get data
|
||||
u8 *ptr = 0;
|
||||
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
|
||||
_class.DoState(p);
|
||||
size_t const sz = (size_t)ptr;
|
||||
|
||||
u8 * buffer = new u8[sz];
|
||||
ptr = &buffer[0];
|
||||
p.SetMode(PointerWrap::MODE_WRITE);
|
||||
_class.DoState(p);
|
||||
|
||||
// Create header
|
||||
SChunkHeader header;
|
||||
header.Compress = compress ? 1 : 0;
|
||||
header.Revision = _Revision;
|
||||
header.ExpectedSize = (int)sz;
|
||||
header.UncompressedSize = (int)sz;
|
||||
|
||||
// Write to file
|
||||
if (compress) {
|
||||
size_t comp_len = snappy_max_compressed_length(sz);
|
||||
u8 *compressed_buffer = new u8[comp_len];
|
||||
snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len);
|
||||
delete [] buffer;
|
||||
header.ExpectedSize = (int)comp_len;
|
||||
if (!pFile.WriteArray(&header, 1))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
|
||||
return false;
|
||||
}
|
||||
if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) {
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data");
|
||||
return false;
|
||||
} else {
|
||||
INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len);
|
||||
}
|
||||
delete [] compressed_buffer;
|
||||
} else {
|
||||
if (!pFile.WriteArray(&header, 1))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
|
||||
return false;
|
||||
}
|
||||
if (!pFile.WriteBytes(&buffer[0], sz))
|
||||
{
|
||||
ERROR_LOG(COMMON,"ChunkReader: Failed writing data");
|
||||
return false;
|
||||
}
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON,"ChunkReader: Done writing %s",
|
||||
_rFilename.c_str());
|
||||
return p.error != p.ERROR_FAILURE;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static bool Verify(T& _class)
|
||||
{
|
||||
u8 *ptr = 0;
|
||||
|
||||
// Step 1: Measure the space required.
|
||||
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
|
||||
_class.DoState(p);
|
||||
size_t const sz = (size_t)ptr;
|
||||
std::vector<u8> buffer(sz);
|
||||
|
||||
// Step 2: Dump the state.
|
||||
ptr = &buffer[0];
|
||||
p.SetMode(PointerWrap::MODE_WRITE);
|
||||
_class.DoState(p);
|
||||
|
||||
// Step 3: Verify the state.
|
||||
ptr = &buffer[0];
|
||||
p.SetMode(PointerWrap::MODE_VERIFY);
|
||||
_class.DoState(p);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct SChunkHeader
|
||||
{
|
||||
int Revision;
|
||||
int Compress;
|
||||
int ExpectedSize;
|
||||
int UncompressedSize;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _POINTERWRAP_H_
|
|
@ -0,0 +1,56 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "ColorUtil.h"
|
||||
|
||||
namespace ColorUtil
|
||||
{
|
||||
|
||||
const int lut5to8[] = { 0x00,0x08,0x10,0x18,0x20,0x29,0x31,0x39,
|
||||
0x41,0x4A,0x52,0x5A,0x62,0x6A,0x73,0x7B,
|
||||
0x83,0x8B,0x94,0x9C,0xA4,0xAC,0xB4,0xBD,
|
||||
0xC5,0xCD,0xD5,0xDE,0xE6,0xEE,0xF6,0xFF };
|
||||
const int lut4to8[] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
|
||||
0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF };
|
||||
const int lut3to8[] = { 0x00,0x24,0x48,0x6D,0x91,0xB6,0xDA,0xFF };
|
||||
|
||||
u32 Decode5A3(u16 val)
|
||||
{
|
||||
const u32 bg_color = 0x00000000;
|
||||
|
||||
int r, g, b, a;
|
||||
|
||||
if (val & 0x8000)
|
||||
{
|
||||
r = lut5to8[(val >> 10) & 0x1f];
|
||||
g = lut5to8[(val >> 5) & 0x1f];
|
||||
b = lut5to8[(val) & 0x1f];
|
||||
a = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = lut3to8[(val >> 12) & 0x7];
|
||||
r = (lut4to8[(val >> 8) & 0xf] * a + (bg_color & 0xFF) * (255 - a)) / 255;
|
||||
g = (lut4to8[(val >> 4) & 0xf] * a + ((bg_color >> 8) & 0xFF) * (255 - a)) / 255;
|
||||
b = (lut4to8[(val) & 0xf] * a + ((bg_color >> 16) & 0xFF) * (255 - a)) / 255;
|
||||
a = 0xFF;
|
||||
}
|
||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,28 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _COLORUTIL_H_
|
||||
#define _COLORUTIL_H_
|
||||
|
||||
namespace ColorUtil
|
||||
{
|
||||
|
||||
u32 Decode5A3(u16 val);
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // _COLORUTIL_H_
|
|
@ -0,0 +1,205 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
// DO NOT EVER INCLUDE <windows.h> directly _or indirectly_ from this file
|
||||
// since it slows down the build a lot.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable:4100)
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
#if !defined(ARM)
|
||||
#define ARM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ARM)
|
||||
#define _M_ARM32
|
||||
#endif
|
||||
|
||||
// SVN version number
|
||||
extern const char *scm_rev_str;
|
||||
extern const char *netplay_dolphin_ver;
|
||||
|
||||
// Force enable logging in the right modes. For some reason, something had changed
|
||||
// so that debugfast no longer logged.
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#undef LOGGING
|
||||
#define LOGGING 1
|
||||
#endif
|
||||
|
||||
#define STACKALIGN
|
||||
|
||||
// An inheritable class to disallow the copy constructor and operator= functions
|
||||
class NonCopyable
|
||||
{
|
||||
protected:
|
||||
NonCopyable() {}
|
||||
private:
|
||||
NonCopyable(const NonCopyable&);
|
||||
void operator=(const NonCopyable&);
|
||||
};
|
||||
|
||||
#include "Log.h"
|
||||
#include "CommonTypes.h"
|
||||
#include "MsgHandler.h"
|
||||
#include "CommonFuncs.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
// The Darwin ABI requires that stack frames be aligned to 16-byte boundaries.
|
||||
// This is only needed on i386 gcc - x86_64 already aligns to 16 bytes.
|
||||
#if defined __i386__ && defined __GNUC__
|
||||
#undef STACKALIGN
|
||||
#define STACKALIGN __attribute__((__force_align_arg_pointer__))
|
||||
#endif
|
||||
// We use wxWidgets on OS X only if it is version 2.9+ with Cocoa support.
|
||||
#ifdef __WXOSX_COCOA__
|
||||
#define HAVE_WX 1
|
||||
#define USE_WX 1 // Use wxGLCanvas
|
||||
#endif
|
||||
|
||||
#elif defined _WIN32
|
||||
|
||||
// Check MSC ver
|
||||
#if !defined _MSC_VER || _MSC_VER <= 1000
|
||||
#error needs at least version 1000 of MSC
|
||||
#endif
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
// Memory leak checks
|
||||
#define CHECK_HEAP_INTEGRITY()
|
||||
|
||||
// Alignment
|
||||
#define GC_ALIGNED16(x) __declspec(align(16)) x
|
||||
#define GC_ALIGNED32(x) __declspec(align(32)) x
|
||||
#define GC_ALIGNED64(x) __declspec(align(64)) x
|
||||
#define GC_ALIGNED128(x) __declspec(align(128)) x
|
||||
#define GC_ALIGNED16_DECL(x) __declspec(align(16)) x
|
||||
#define GC_ALIGNED64_DECL(x) __declspec(align(64)) x
|
||||
|
||||
// Since it is always around on windows
|
||||
#define HAVE_WX 1
|
||||
|
||||
#define HAVE_PORTAUDIO 1
|
||||
|
||||
// Debug definitions
|
||||
#if defined(_DEBUG)
|
||||
#include <crtdbg.h>
|
||||
#undef CHECK_HEAP_INTEGRITY
|
||||
#define CHECK_HEAP_INTEGRITY() {if (!_CrtCheckMemory()) PanicAlert("memory corruption detected. see log.");}
|
||||
// If you want to see how much a pain in the ass singletons are, for example:
|
||||
// {614} normal block at 0x030C5310, 188 bytes long.
|
||||
// Data: <Master Log > 4D 61 73 74 65 72 20 4C 6F 67 00 00 00 00 00 00
|
||||
struct CrtDebugBreak { CrtDebugBreak(int spot) { _CrtSetBreakAlloc(spot); } };
|
||||
//CrtDebugBreak breakAt(614);
|
||||
#endif // end DEBUG/FAST
|
||||
|
||||
#endif
|
||||
|
||||
// Windows compatibility
|
||||
#ifndef _WIN32
|
||||
#include <limits.h>
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH PATH_MAX
|
||||
#endif
|
||||
#ifdef _LP64
|
||||
#define _M_X64 1
|
||||
#else
|
||||
#ifndef _M_ARM32
|
||||
#define _M_IX86 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define __forceinline inline __attribute__((always_inline))
|
||||
#define GC_ALIGNED16(x) __attribute__((aligned(16))) x
|
||||
#define GC_ALIGNED32(x) __attribute__((aligned(32))) x
|
||||
#define GC_ALIGNED64(x) __attribute__((aligned(64))) x
|
||||
#define GC_ALIGNED128(x) __attribute__((aligned(128))) x
|
||||
#define GC_ALIGNED16_DECL(x) __attribute__((aligned(16))) x
|
||||
#define GC_ALIGNED64_DECL(x) __attribute__((aligned(64))) x
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define __strdup _strdup
|
||||
#define __getcwd _getcwd
|
||||
#define __chdir _chdir
|
||||
#else
|
||||
#define __strdup strdup
|
||||
#define __getcwd getcwd
|
||||
#define __chdir chdir
|
||||
#endif
|
||||
|
||||
// Dummy macro for marking translatable strings that can not be immediately translated.
|
||||
// wxWidgets does not have a true dummy macro for this.
|
||||
#define _trans(a) a
|
||||
|
||||
#if defined __GNUC__
|
||||
# if defined __SSE4_2__
|
||||
# define _M_SSE 0x402
|
||||
# elif defined __SSE4_1__
|
||||
# define _M_SSE 0x401
|
||||
# elif defined __SSSE3__
|
||||
# define _M_SSE 0x301
|
||||
# elif defined __SSE3__
|
||||
# define _M_SSE 0x300
|
||||
# endif
|
||||
#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
|
||||
# define _M_SSE 0x402
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
inline unsigned int bswap32(unsigned int x) { return _byteswap_ulong(x); }
|
||||
inline unsigned int bswap16(unsigned int x) { return _byteswap_ushort(x); }
|
||||
#else
|
||||
// TODO: speedup
|
||||
inline unsigned int bswap32(unsigned int x) { return (x >> 24) | ((x & 0xFF0000) >> 8) | ((x & 0xFF00) << 8) | (x << 24);}
|
||||
inline unsigned short bswap16(unsigned short x) { return (x << 8) | (x >> 8); }
|
||||
#endif
|
||||
|
||||
|
||||
// Host communication.
|
||||
enum HOST_COMM
|
||||
{
|
||||
// Begin at 10 in case there is already messages with wParam = 0, 1, 2 and so on
|
||||
WM_USER_STOP = 10,
|
||||
WM_USER_CREATE,
|
||||
WM_USER_SETCURSOR,
|
||||
WM_USER_KEYDOWN,
|
||||
};
|
||||
|
||||
// Used for notification on emulation state
|
||||
enum EMUSTATE_CHANGE
|
||||
{
|
||||
EMUSTATE_CHANGE_PLAY = 1,
|
||||
EMUSTATE_CHANGE_PAUSE,
|
||||
EMUSTATE_CHANGE_STOP
|
||||
};
|
||||
|
||||
#endif // _COMMON_H_
|
|
@ -0,0 +1,260 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{3FCDBAE2-5103-4350-9A8E-848CE9C73195}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Common</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>../native</AdditionalIncludeDirectories>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>Winmm.lib</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../native</AdditionalIncludeDirectories>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>Winmm.lib</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<AdditionalIncludeDirectories>../native</AdditionalIncludeDirectories>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>Winmm.lib</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<AdditionalIncludeDirectories>../native</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>Winmm.lib</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ABI.h" />
|
||||
<ClInclude Include="ArmEmitter.h" />
|
||||
<ClInclude Include="Atomics.h" />
|
||||
<ClInclude Include="Atomic_GCC.h" />
|
||||
<ClInclude Include="Atomic_Win32.h" />
|
||||
<ClInclude Include="ChunkFile.h" />
|
||||
<ClInclude Include="ColorUtil.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="CommonFuncs.h" />
|
||||
<ClInclude Include="CommonPaths.h" />
|
||||
<ClInclude Include="CommonTypes.h" />
|
||||
<ClInclude Include="ConsoleListener.h" />
|
||||
<ClInclude Include="CPUDetect.h" />
|
||||
<ClInclude Include="Crypto\md5.h" />
|
||||
<ClInclude Include="DebugInterface.h" />
|
||||
<ClInclude Include="ExtendedTrace.h" />
|
||||
<ClInclude Include="FifoQueue.h" />
|
||||
<ClInclude Include="FileSearch.h" />
|
||||
<ClInclude Include="FileUtil.h" />
|
||||
<ClInclude Include="FixedSizeQueue.h" />
|
||||
<ClInclude Include="FixedSizeUnorderedSet.h" />
|
||||
<ClInclude Include="Hash.h" />
|
||||
<ClInclude Include="LinearDiskCache.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="LogManager.h" />
|
||||
<ClInclude Include="MathUtil.h" />
|
||||
<ClInclude Include="MemArena.h" />
|
||||
<ClInclude Include="MemoryUtil.h" />
|
||||
<ClInclude Include="MsgHandler.h" />
|
||||
<ClInclude Include="scmrev.h" />
|
||||
<ClInclude Include="Setup.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="StdConditionVariable.h" />
|
||||
<ClInclude Include="StdMutex.h" />
|
||||
<ClInclude Include="StdThread.h" />
|
||||
<ClInclude Include="StringUtils.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="Thread.h" />
|
||||
<ClInclude Include="ThreadPools.h" />
|
||||
<ClInclude Include="Thunk.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ABI.cpp" />
|
||||
<ClCompile Include="ArmCPUDetect.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ArmEmitter.cpp" />
|
||||
<ClCompile Include="ColorUtil.cpp" />
|
||||
<ClCompile Include="ConsoleListener.cpp" />
|
||||
<ClCompile Include="CPUDetect.cpp" />
|
||||
<ClCompile Include="Crypto\md5.cpp" />
|
||||
<ClCompile Include="ExtendedTrace.cpp" />
|
||||
<ClCompile Include="FileSearch.cpp" />
|
||||
<ClCompile Include="FileUtil.cpp" />
|
||||
<ClCompile Include="Hash.cpp" />
|
||||
<ClCompile Include="LogManager.cpp" />
|
||||
<ClCompile Include="MathUtil.cpp" />
|
||||
<ClCompile Include="MemArena.cpp" />
|
||||
<ClCompile Include="MemoryUtil.cpp" />
|
||||
<ClCompile Include="Misc.cpp" />
|
||||
<ClCompile Include="MsgHandler.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StringUtils.cpp" />
|
||||
<ClCompile Include="Thread.cpp" />
|
||||
<ClCompile Include="ThreadPools.cpp" />
|
||||
<ClCompile Include="Thunk.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="Version.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\native\native.vcxproj">
|
||||
<Project>{c4df647e-80ea-4111-a0a8-218b1b711e18}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="ABI.h" />
|
||||
<ClInclude Include="Atomics.h" />
|
||||
<ClInclude Include="Atomic_GCC.h" />
|
||||
<ClInclude Include="Atomic_Win32.h" />
|
||||
<ClInclude Include="ChunkFile.h" />
|
||||
<ClInclude Include="ColorUtil.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="CommonFuncs.h" />
|
||||
<ClInclude Include="CommonPaths.h" />
|
||||
<ClInclude Include="CommonTypes.h" />
|
||||
<ClInclude Include="ConsoleListener.h" />
|
||||
<ClInclude Include="CPUDetect.h" />
|
||||
<ClInclude Include="DebugInterface.h" />
|
||||
<ClInclude Include="ExtendedTrace.h" />
|
||||
<ClInclude Include="FifoQueue.h" />
|
||||
<ClInclude Include="FileSearch.h" />
|
||||
<ClInclude Include="FileUtil.h" />
|
||||
<ClInclude Include="FixedSizeQueue.h" />
|
||||
<ClInclude Include="Hash.h" />
|
||||
<ClInclude Include="LinearDiskCache.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="LogManager.h" />
|
||||
<ClInclude Include="MathUtil.h" />
|
||||
<ClInclude Include="MemArena.h" />
|
||||
<ClInclude Include="MemoryUtil.h" />
|
||||
<ClInclude Include="MsgHandler.h" />
|
||||
<ClInclude Include="scmrev.h" />
|
||||
<ClInclude Include="Setup.h" />
|
||||
<ClInclude Include="StdConditionVariable.h" />
|
||||
<ClInclude Include="StdMutex.h" />
|
||||
<ClInclude Include="StdThread.h" />
|
||||
<ClInclude Include="StringUtils.h" />
|
||||
<ClInclude Include="Thread.h" />
|
||||
<ClInclude Include="Thunk.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
<ClInclude Include="ArmEmitter.h" />
|
||||
<ClInclude Include="FixedSizeUnorderedSet.h" />
|
||||
<ClInclude Include="ThreadPools.h" />
|
||||
<ClInclude Include="Crypto\md5.h">
|
||||
<Filter>Crypto</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
<ClCompile Include="ABI.cpp" />
|
||||
<ClCompile Include="ColorUtil.cpp" />
|
||||
<ClCompile Include="ConsoleListener.cpp" />
|
||||
<ClCompile Include="CPUDetect.cpp" />
|
||||
<ClCompile Include="ExtendedTrace.cpp" />
|
||||
<ClCompile Include="FileSearch.cpp" />
|
||||
<ClCompile Include="FileUtil.cpp" />
|
||||
<ClCompile Include="Hash.cpp" />
|
||||
<ClCompile Include="LogManager.cpp" />
|
||||
<ClCompile Include="MathUtil.cpp" />
|
||||
<ClCompile Include="MemArena.cpp" />
|
||||
<ClCompile Include="MemoryUtil.cpp" />
|
||||
<ClCompile Include="Misc.cpp" />
|
||||
<ClCompile Include="MsgHandler.cpp" />
|
||||
<ClCompile Include="StringUtils.cpp" />
|
||||
<ClCompile Include="Thread.cpp" />
|
||||
<ClCompile Include="Thunk.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="Version.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
<ClCompile Include="ArmEmitter.cpp" />
|
||||
<ClCompile Include="ArmCPUDetect.cpp" />
|
||||
<ClCompile Include="ThreadPools.cpp" />
|
||||
<ClCompile Include="Crypto\md5.cpp">
|
||||
<Filter>Crypto</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Crypto">
|
||||
<UniqueIdentifier>{1b593f03-7b28-4707-9228-4981796f5589}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,158 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SLEEP(x) Sleep(x)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#define SLEEP(x) usleep(x*1000)
|
||||
#endif
|
||||
|
||||
#if defined(IOS) || defined(MIPS)
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
template <bool> struct CompileTimeAssert;
|
||||
template<> struct CompileTimeAssert<true> {};
|
||||
|
||||
#define b2(x) ( (x) | ( (x) >> 1) )
|
||||
#define b4(x) ( b2(x) | ( b2(x) >> 2) )
|
||||
#define b8(x) ( b4(x) | ( b4(x) >> 4) )
|
||||
#define b16(x) ( b8(x) | ( b8(x) >> 8) )
|
||||
#define b32(x) (b16(x) | (b16(x) >>16) )
|
||||
#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <errno.h>
|
||||
#ifdef __linux__
|
||||
#include <byteswap.h>
|
||||
#elif defined __FreeBSD__
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
// go to debugger mode
|
||||
#ifdef GEKKO
|
||||
#define Crash()
|
||||
#else
|
||||
// Assume !ARM && !MIPS = x86
|
||||
#if !defined(ARM) && !defined(MIPS)
|
||||
#define Crash() {asm ("int $3");}
|
||||
#else
|
||||
#define Crash() {kill( getpid(), SIGINT ) ; }
|
||||
#endif
|
||||
#endif
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
|
||||
inline u32 __rotl(u32 x, int shift) {
|
||||
shift &= 31;
|
||||
if (!shift) return x;
|
||||
return (x << shift) | (x >> (32 - shift));
|
||||
}
|
||||
|
||||
inline u64 __rotl64(u64 x, unsigned int shift){
|
||||
unsigned int n = shift % 64;
|
||||
return (x << n) | (x >> (64 - n));
|
||||
}
|
||||
|
||||
inline u32 __rotr(u32 x, int shift) {
|
||||
shift &= 31;
|
||||
if (!shift) return x;
|
||||
return (x >> shift) | (x << (32 - shift));
|
||||
}
|
||||
|
||||
inline u64 __rotr64(u64 x, unsigned int shift){
|
||||
unsigned int n = shift % 64;
|
||||
return (x >> n) | (x << (64 - n));
|
||||
}
|
||||
|
||||
#else // WIN32
|
||||
// Function Cross-Compatibility
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#define unlink _unlink
|
||||
#define snprintf _snprintf
|
||||
#define vscprintf _vscprintf
|
||||
#define __rotl _rotl
|
||||
#define __rotl64 _rotl64
|
||||
#define __rotr _rotr
|
||||
#define __rotr64 _rotr64
|
||||
|
||||
// 64 bit offsets for windows
|
||||
#define fseeko _fseeki64
|
||||
#define ftello _ftelli64
|
||||
#define atoll _atoi64
|
||||
#define stat64 _stat64
|
||||
#define fstat64 _fstat64
|
||||
#define fileno _fileno
|
||||
|
||||
#if _M_IX86
|
||||
#define Crash() {__asm int 3}
|
||||
#else
|
||||
extern "C" {
|
||||
__declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
}
|
||||
#define Crash() {DebugBreak();}
|
||||
#endif // M_IX86
|
||||
#endif // WIN32 ndef
|
||||
|
||||
// Generic function to get last error message.
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
// Defined in Misc.cpp.
|
||||
const char* GetLastErrorMsg();
|
||||
|
||||
namespace Common
|
||||
{
|
||||
inline u8 swap8(u8 _data) {return _data;}
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef swap32
|
||||
inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);}
|
||||
inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);}
|
||||
inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);}
|
||||
/*
|
||||
#elif __linux__
|
||||
inline u16 swap16(u16 _data) {return bswap_16(_data);}
|
||||
inline u32 swap32(u32 _data) {return bswap_32(_data);}
|
||||
inline u64 swap64(u64 _data) {return bswap_64(_data);}
|
||||
#elif __APPLE__
|
||||
inline __attribute__((always_inline)) u16 swap16(u16 _data)
|
||||
{return (_data >> 8) | (_data << 8);}
|
||||
inline __attribute__((always_inline)) u32 swap32(u32 _data)
|
||||
{return __builtin_bswap32(_data);}
|
||||
inline __attribute__((always_inline)) u64 swap64(u64 _data)
|
||||
{return __builtin_bswap64(_data);}
|
||||
#elif __FreeBSD__
|
||||
inline u16 swap16(u16 _data) {return bswap16(_data);}
|
||||
inline u32 swap32(u32 _data) {return bswap32(_data);}
|
||||
inline u64 swap64(u64 _data) {return bswap64(_data);}
|
||||
*/
|
||||
#else
|
||||
// Slow generic implementation.
|
||||
//inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);}
|
||||
//inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);}
|
||||
//inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);}
|
||||
#endif
|
||||
|
||||
//inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);}
|
||||
//inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);}
|
||||
//inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);}
|
||||
|
||||
} // Namespace Common
|
|
@ -0,0 +1,118 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _COMMON_PATHS_H_
|
||||
#define _COMMON_PATHS_H_
|
||||
|
||||
// Make sure we pick up USER_DIR if set in config.h
|
||||
#include "Common.h"
|
||||
|
||||
// Directory seperators, do we need this?
|
||||
#define DIR_SEP "/"
|
||||
#ifdef _WIN32
|
||||
#define DIR_SEP_CHRS "/\\"
|
||||
#else
|
||||
#define DIR_SEP_CHRS "/"
|
||||
#endif
|
||||
|
||||
// The user data dir
|
||||
#define ROOT_DIR "."
|
||||
#ifdef _WIN32
|
||||
#define USERDATA_DIR "User"
|
||||
#define DOLPHIN_DATA_DIR "Dolphin"
|
||||
#elif defined __APPLE__
|
||||
// On OS X, USERDATA_DIR exists within the .app, but *always* reference
|
||||
// the copy in Application Support instead! (Copied on first run)
|
||||
// You can use the File::GetUserPath() util for this
|
||||
#define USERDATA_DIR "Contents/Resources/User"
|
||||
#define DOLPHIN_DATA_DIR "Library/Application Support/Dolphin"
|
||||
#else
|
||||
#define USERDATA_DIR "user"
|
||||
#ifdef USER_DIR
|
||||
#define DOLPHIN_DATA_DIR USER_DIR
|
||||
#else
|
||||
#define DOLPHIN_DATA_DIR ".dolphin"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Shared data dirs (Sys and shared User for linux)
|
||||
#ifdef _WIN32
|
||||
#define SYSDATA_DIR "Sys"
|
||||
#elif defined __APPLE__
|
||||
#define SYSDATA_DIR "Contents/Resources/Sys"
|
||||
#define SHARED_USER_DIR File::GetBundleDirectory() + \
|
||||
DIR_SEP USERDATA_DIR DIR_SEP
|
||||
#else
|
||||
#ifdef DATA_DIR
|
||||
#define SYSDATA_DIR DATA_DIR "sys"
|
||||
#define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP
|
||||
#else
|
||||
#define SYSDATA_DIR "sys"
|
||||
#define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Dirs in both User and Sys
|
||||
#define EUR_DIR "EUR"
|
||||
#define USA_DIR "USA"
|
||||
#define JAP_DIR "JAP"
|
||||
|
||||
// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
|
||||
#define GC_USER_DIR "GC"
|
||||
#define WII_USER_DIR "Wii"
|
||||
#define CONFIG_DIR "Config"
|
||||
#define GAMECONFIG_DIR "GameConfig"
|
||||
#define MAPS_DIR "Maps"
|
||||
#define CACHE_DIR "Cache"
|
||||
#define SHADERCACHE_DIR "ShaderCache"
|
||||
#define STATESAVES_DIR "StateSaves"
|
||||
#define SCREENSHOTS_DIR "ScreenShots"
|
||||
#define OPENCL_DIR "OpenCL"
|
||||
#define LOAD_DIR "Load"
|
||||
#define HIRES_TEXTURES_DIR LOAD_DIR DIR_SEP "Textures"
|
||||
#define DUMP_DIR "Dump"
|
||||
#define DUMP_TEXTURES_DIR DUMP_DIR DIR_SEP "Textures"
|
||||
#define DUMP_FRAMES_DIR DUMP_DIR DIR_SEP "Frames"
|
||||
#define DUMP_AUDIO_DIR DUMP_DIR DIR_SEP "Audio"
|
||||
#define DUMP_DSP_DIR DUMP_DIR DIR_SEP "DSP"
|
||||
#define LOGS_DIR "Logs"
|
||||
#define MAIL_LOGS_DIR LOGS_DIR DIR_SEP "Mail"
|
||||
#define SHADERS_DIR "Shaders"
|
||||
#define WII_SYSCONF_DIR "shared2" DIR_SEP "sys"
|
||||
|
||||
// Filenames
|
||||
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
|
||||
#define CONFIG_FILE "ppsspp.ini"
|
||||
#define LOGGER_CONFIG "Logger.ini"
|
||||
|
||||
// Files in the directory returned by GetUserPath(D_LOGS_IDX)
|
||||
#define MAIN_LOG "ppsspp.log"
|
||||
|
||||
// Sys files
|
||||
#define TOTALDB "totaldb.dsy"
|
||||
|
||||
#define FONT_ANSI "font_ansi.bin"
|
||||
#define FONT_SJIS "font_sjis.bin"
|
||||
|
||||
#define DSP_IROM "dsp_rom.bin"
|
||||
#define DSP_COEF "dsp_coef.bin"
|
||||
|
||||
// Subdirs in Sys
|
||||
#define GC_SYS_DIR "GC"
|
||||
#define WII_SYS_DIR "Wii"
|
||||
|
||||
#endif // _COMMON_PATHS_H_
|
|
@ -0,0 +1,58 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
|
||||
// This header contains type definitions that are shared between the Dolphin core and
|
||||
// other parts of the code. Any definitions that are only used by the core should be
|
||||
// placed in "Common.h" instead.
|
||||
|
||||
#ifndef _COMMONTYPES_H_
|
||||
#define _COMMONTYPES_H_
|
||||
|
||||
#ifdef __arm__
|
||||
#if !defined(ARM)
|
||||
#define ARM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef unsigned __int8 u8;
|
||||
typedef unsigned __int16 u16;
|
||||
typedef unsigned __int32 u32;
|
||||
typedef unsigned __int64 u64;
|
||||
|
||||
typedef signed __int8 s8;
|
||||
typedef signed __int16 s16;
|
||||
typedef signed __int32 s32;
|
||||
typedef signed __int64 s64;
|
||||
|
||||
#else
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
typedef signed char s8;
|
||||
typedef signed short s16;
|
||||
typedef signed int s32;
|
||||
typedef signed long long s64;
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // _COMMONTYPES_H_
|
|
@ -0,0 +1,592 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 <algorithm> // min
|
||||
#include <string> // System: To be able to add strings with "+"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <array>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "LogManager.h" // Common
|
||||
#include "ConsoleListener.h" // Common
|
||||
#include "Atomics.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
const int LOG_PENDING_MAX = 120 * 10000;
|
||||
const int LOG_LATENCY_DELAY_MS = 20;
|
||||
const int LOG_SHUTDOWN_DELAY_MS = 250;
|
||||
const int LOG_MAX_DISPLAY_LINES = 4000;
|
||||
|
||||
int ConsoleListener::refCount = 0;
|
||||
HANDLE ConsoleListener::hThread = NULL;
|
||||
HANDLE ConsoleListener::hTriggerEvent = NULL;
|
||||
CRITICAL_SECTION ConsoleListener::criticalSection;
|
||||
|
||||
char *ConsoleListener::logPending = NULL;
|
||||
volatile u32 ConsoleListener::logPendingReadPos = 0;
|
||||
volatile u32 ConsoleListener::logPendingWritePos = 0;
|
||||
#endif
|
||||
|
||||
ConsoleListener::ConsoleListener()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
hConsole = NULL;
|
||||
bUseColor = true;
|
||||
|
||||
if (hTriggerEvent == NULL)
|
||||
{
|
||||
hTriggerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
InitializeCriticalSection(&criticalSection);
|
||||
}
|
||||
++refCount;
|
||||
#else
|
||||
bUseColor = isatty(fileno(stdout));
|
||||
#endif
|
||||
}
|
||||
|
||||
ConsoleListener::~ConsoleListener()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
// 100, 100, "Dolphin Log Console"
|
||||
// Open console window - width and height is the size of console window
|
||||
// Name is the window title
|
||||
void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title)
|
||||
{
|
||||
bHidden = Hidden;
|
||||
#ifdef _WIN32
|
||||
if (!GetConsoleWindow())
|
||||
{
|
||||
// Open the console window and create the window handle for GetStdHandle()
|
||||
AllocConsole();
|
||||
HWND hConWnd = GetConsoleWindow();
|
||||
ShowWindow(hConWnd, SW_SHOWDEFAULT);
|
||||
// Hide
|
||||
if (Hidden) ShowWindow(hConWnd, SW_HIDE);
|
||||
// Save the window handle that AllocConsole() created
|
||||
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
// Set the console window title
|
||||
SetConsoleTitle(Title);
|
||||
// Set letter space
|
||||
LetterSpace(Width, LOG_MAX_DISPLAY_LINES);
|
||||
//MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
if (hTriggerEvent != NULL && hThread == NULL)
|
||||
{
|
||||
logPending = new char[LOG_PENDING_MAX];
|
||||
hThread = (HANDLE)_beginthreadex(NULL, 0, &ConsoleListener::RunThread, this, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConsoleListener::Show(bool bShow)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (bShow && bHidden)
|
||||
{
|
||||
ShowWindow(GetConsoleWindow(), SW_SHOW);
|
||||
bHidden = false;
|
||||
}
|
||||
else if (!bShow && !bHidden)
|
||||
{
|
||||
ShowWindow(GetConsoleWindow(), SW_HIDE);
|
||||
bHidden = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void ConsoleListener::UpdateHandle()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Close the console window and close the eventual file handle
|
||||
void ConsoleListener::Close()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (hConsole == NULL)
|
||||
return;
|
||||
|
||||
if (--refCount <= 0)
|
||||
{
|
||||
if (hThread != NULL)
|
||||
{
|
||||
Common::AtomicStoreRelease(logPendingWritePos, (u32) -1);
|
||||
|
||||
SetEvent(hTriggerEvent);
|
||||
WaitForSingleObject(hThread, LOG_SHUTDOWN_DELAY_MS);
|
||||
CloseHandle(hThread);
|
||||
hThread = NULL;
|
||||
}
|
||||
if (hTriggerEvent != NULL)
|
||||
{
|
||||
DeleteCriticalSection(&criticalSection);
|
||||
CloseHandle(hTriggerEvent);
|
||||
hTriggerEvent = NULL;
|
||||
}
|
||||
if (logPending != NULL)
|
||||
{
|
||||
delete [] logPending;
|
||||
logPending = NULL;
|
||||
}
|
||||
refCount = 0;
|
||||
}
|
||||
|
||||
FreeConsole();
|
||||
hConsole = NULL;
|
||||
#else
|
||||
fflush(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ConsoleListener::IsOpen()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (hConsole != NULL);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are
|
||||
dependent on each other, that's the reason for the additional checks.
|
||||
*/
|
||||
void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
BOOL SB, SW;
|
||||
if (BufferFirst)
|
||||
{
|
||||
// Change screen buffer size
|
||||
COORD Co = {BufferWidth, BufferHeight};
|
||||
SB = SetConsoleScreenBufferSize(hConsole, Co);
|
||||
// Change the screen buffer window size
|
||||
SMALL_RECT coo = {0,0,ScreenWidth, ScreenHeight}; // top, left, right, bottom
|
||||
SW = SetConsoleWindowInfo(hConsole, TRUE, &coo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change the screen buffer window size
|
||||
SMALL_RECT coo = {0,0, ScreenWidth, ScreenHeight}; // top, left, right, bottom
|
||||
SW = SetConsoleWindowInfo(hConsole, TRUE, &coo);
|
||||
// Change screen buffer size
|
||||
COORD Co = {BufferWidth, BufferHeight};
|
||||
SB = SetConsoleScreenBufferSize(hConsole, Co);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void ConsoleListener::LetterSpace(int Width, int Height)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Get console info
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
|
||||
GetConsoleScreenBufferInfo(hConsole, &ConInfo);
|
||||
|
||||
//
|
||||
int OldBufferWidth = ConInfo.dwSize.X;
|
||||
int OldBufferHeight = ConInfo.dwSize.Y;
|
||||
int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left);
|
||||
int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top);
|
||||
//
|
||||
int NewBufferWidth = Width;
|
||||
int NewBufferHeight = Height;
|
||||
int NewScreenWidth = NewBufferWidth - 1;
|
||||
int NewScreenHeight = OldScreenHeight;
|
||||
|
||||
// Width
|
||||
BufferWidthHeight(NewBufferWidth, OldBufferHeight, NewScreenWidth, OldScreenHeight, (NewBufferWidth > OldScreenWidth-1));
|
||||
// Height
|
||||
BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1));
|
||||
|
||||
// Resize the window too
|
||||
//MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth)
|
||||
{
|
||||
COORD Ret = {0, 0};
|
||||
// Full rows
|
||||
int Step = (int)floor((float)BytesRead / (float)BufferWidth);
|
||||
Ret.Y += Step;
|
||||
// Partial row
|
||||
Ret.X = BytesRead - (BufferWidth * Step);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
unsigned int WINAPI ConsoleListener::RunThread(void *lpParam)
|
||||
{
|
||||
ConsoleListener *consoleLog = (ConsoleListener *)lpParam;
|
||||
consoleLog->LogWriterThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConsoleListener::LogWriterThread()
|
||||
{
|
||||
char *logLocal = new char[LOG_PENDING_MAX];
|
||||
int logLocalSize = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
WaitForSingleObject(hTriggerEvent, INFINITE);
|
||||
Sleep(LOG_LATENCY_DELAY_MS);
|
||||
|
||||
u32 logRemotePos = Common::AtomicLoadAcquire(logPendingWritePos);
|
||||
if (logRemotePos == (u32) -1)
|
||||
break;
|
||||
else if (logRemotePos == logPendingReadPos)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
EnterCriticalSection(&criticalSection);
|
||||
logRemotePos = Common::AtomicLoadAcquire(logPendingWritePos);
|
||||
|
||||
int start = 0;
|
||||
if (logRemotePos < logPendingReadPos)
|
||||
{
|
||||
const int count = LOG_PENDING_MAX - logPendingReadPos;
|
||||
memcpy(logLocal + start, logPending + logPendingReadPos, count);
|
||||
|
||||
start = count;
|
||||
logPendingReadPos = 0;
|
||||
}
|
||||
|
||||
const int count = logRemotePos - logPendingReadPos;
|
||||
memcpy(logLocal + start, logPending + logPendingReadPos, count);
|
||||
|
||||
logPendingReadPos += count;
|
||||
LeaveCriticalSection(&criticalSection);
|
||||
|
||||
// Double check.
|
||||
if (logPendingWritePos == (u32) -1)
|
||||
break;
|
||||
|
||||
logLocalSize = start + count;
|
||||
}
|
||||
|
||||
for (char *Text = logLocal, *End = logLocal + logLocalSize; Text < End; )
|
||||
{
|
||||
LogTypes::LOG_LEVELS Level = LogTypes::LINFO;
|
||||
|
||||
char *next = (char *) memchr(Text + 1, '\033', End - Text);
|
||||
size_t Len = next - Text;
|
||||
if (next == NULL)
|
||||
Len = End - Text;
|
||||
|
||||
if (Text[0] == '\033' && Text + 1 < End)
|
||||
{
|
||||
Level = (LogTypes::LOG_LEVELS) (Text[1] - '0');
|
||||
Len -= 2;
|
||||
Text += 2;
|
||||
}
|
||||
|
||||
// Make sure we didn't start quitting. This is kinda slow.
|
||||
if (logPendingWritePos == (u32) -1)
|
||||
break;
|
||||
|
||||
WriteToConsole(Level, Text, Len);
|
||||
Text += Len;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] logLocal;
|
||||
}
|
||||
|
||||
void ConsoleListener::SendToThread(LogTypes::LOG_LEVELS Level, const char *Text)
|
||||
{
|
||||
// Oops, we're already quitting. Just do nothing.
|
||||
if (logPendingWritePos == (u32) -1)
|
||||
return;
|
||||
|
||||
int Len = (int)strlen(Text);
|
||||
if (Len > LOG_PENDING_MAX)
|
||||
Len = LOG_PENDING_MAX - 16;
|
||||
|
||||
char ColorAttr[16] = "";
|
||||
int ColorLen = 0;
|
||||
if (bUseColor)
|
||||
{
|
||||
// Not ANSI, since the console doesn't support it, but ANSI-like.
|
||||
snprintf(ColorAttr, 16, "\033%d", Level);
|
||||
// For now, rather than properly support it.
|
||||
_dbg_assert_msg_(COMMON, strlen(ColorAttr) == 2, "Console logging doesn't support > 9 levels.");
|
||||
ColorLen = (int)strlen(ColorAttr);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&criticalSection);
|
||||
u32 logWritePos = Common::AtomicLoad(logPendingWritePos);
|
||||
u32 prevLogWritePos = logWritePos;
|
||||
if (logWritePos + ColorLen + Len >= LOG_PENDING_MAX)
|
||||
{
|
||||
for (int i = 0; i < ColorLen; ++i)
|
||||
logPending[(logWritePos + i) % LOG_PENDING_MAX] = ColorAttr[i];
|
||||
logWritePos += ColorLen;
|
||||
if (logWritePos >= LOG_PENDING_MAX)
|
||||
logWritePos -= LOG_PENDING_MAX;
|
||||
|
||||
int start = 0;
|
||||
if (logWritePos < LOG_PENDING_MAX && logWritePos + Len >= LOG_PENDING_MAX)
|
||||
{
|
||||
const int count = LOG_PENDING_MAX - logWritePos;
|
||||
memcpy(logPending + logWritePos, Text, count);
|
||||
start = count;
|
||||
logWritePos = 0;
|
||||
}
|
||||
const int count = Len - start;
|
||||
if (count > 0)
|
||||
{
|
||||
memcpy(logPending + logWritePos, Text + start, count);
|
||||
logWritePos += count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(logPending + logWritePos, ColorAttr, ColorLen);
|
||||
memcpy(logPending + logWritePos + ColorLen, Text, Len);
|
||||
logWritePos += ColorLen + Len;
|
||||
}
|
||||
|
||||
// Oops, we passed the read pos.
|
||||
if (prevLogWritePos < logPendingReadPos && logWritePos >= logPendingReadPos)
|
||||
{
|
||||
char *nextNewline = (char *) memchr(logPending + logWritePos, '\n', LOG_PENDING_MAX - logWritePos);
|
||||
if (nextNewline == NULL && logWritePos > 0)
|
||||
nextNewline = (char *) memchr(logPending, '\n', logWritePos);
|
||||
|
||||
// Okay, have it go right after the next newline.
|
||||
if (nextNewline != NULL)
|
||||
logPendingReadPos = (u32)(nextNewline - logPending + 1);
|
||||
}
|
||||
|
||||
// Double check we didn't start quitting.
|
||||
if (logPendingWritePos == (u32) -1)
|
||||
return;
|
||||
|
||||
Common::AtomicStoreRelease(logPendingWritePos, logWritePos);
|
||||
LeaveCriticalSection(&criticalSection);
|
||||
|
||||
SetEvent(hTriggerEvent);
|
||||
}
|
||||
|
||||
void ConsoleListener::WriteToConsole(LogTypes::LOG_LEVELS Level, const char *Text, size_t Len)
|
||||
{
|
||||
/*
|
||||
const int MAX_BYTES = 1024*10;
|
||||
char Str[MAX_BYTES];
|
||||
va_list ArgPtr;
|
||||
int Cnt;
|
||||
va_start(ArgPtr, Text);
|
||||
Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr);
|
||||
va_end(ArgPtr);
|
||||
*/
|
||||
DWORD cCharsWritten;
|
||||
WORD Color;
|
||||
|
||||
switch (Level)
|
||||
{
|
||||
case NOTICE_LEVEL: // light green
|
||||
Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case ERROR_LEVEL: // light red
|
||||
Color = FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case WARNING_LEVEL: // light yellow
|
||||
Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case INFO_LEVEL: // cyan
|
||||
Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case DEBUG_LEVEL: // gray
|
||||
Color = FOREGROUND_INTENSITY;
|
||||
break;
|
||||
default: // off-white
|
||||
Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
break;
|
||||
}
|
||||
if (Len > 10)
|
||||
{
|
||||
// First 10 chars white
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL);
|
||||
Text += 10;
|
||||
Len -= 10;
|
||||
}
|
||||
SetConsoleTextAttribute(hConsole, Color);
|
||||
WriteConsole(hConsole, Text, (DWORD)Len, &cCharsWritten, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Check size
|
||||
if (Width < 8 || Height < 12) return;
|
||||
|
||||
bool DBef = true;
|
||||
bool DAft = true;
|
||||
std::string SLog = "";
|
||||
|
||||
const HWND hWnd = GetConsoleWindow();
|
||||
const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
// Get console info
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
|
||||
GetConsoleScreenBufferInfo(hConsole, &ConInfo);
|
||||
DWORD BufferSize = ConInfo.dwSize.X * ConInfo.dwSize.Y;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Save the current text
|
||||
// ------------------------
|
||||
DWORD cCharsRead = 0;
|
||||
COORD coordScreen = { 0, 0 };
|
||||
|
||||
static const int MAX_BYTES = 1024 * 16;
|
||||
|
||||
std::vector<std::array<CHAR, MAX_BYTES>> Str;
|
||||
std::vector<std::array<WORD, MAX_BYTES>> Attr;
|
||||
|
||||
// ReadConsoleOutputAttribute seems to have a limit at this level
|
||||
static const int ReadBufferSize = MAX_BYTES - 32;
|
||||
|
||||
DWORD cAttrRead = ReadBufferSize;
|
||||
DWORD BytesRead = 0;
|
||||
while (BytesRead < BufferSize)
|
||||
{
|
||||
Str.resize(Str.size() + 1);
|
||||
if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead))
|
||||
SLog += StringFromFormat("WriteConsoleOutputCharacter error");
|
||||
|
||||
Attr.resize(Attr.size() + 1);
|
||||
if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead))
|
||||
SLog += StringFromFormat("WriteConsoleOutputAttribute error");
|
||||
|
||||
// Break on error
|
||||
if (cAttrRead == 0) break;
|
||||
BytesRead += cAttrRead;
|
||||
coordScreen = GetCoordinates(BytesRead, ConInfo.dwSize.X);
|
||||
}
|
||||
// Letter space
|
||||
int LWidth = (int)(floor((float)Width / 8.0f) - 1.0f);
|
||||
int LHeight = (int)(floor((float)Height / 12.0f) - 1.0f);
|
||||
int LBufWidth = LWidth + 1;
|
||||
int LBufHeight = (int)floor((float)BufferSize / (float)LBufWidth);
|
||||
// Change screen buffer size
|
||||
LetterSpace(LBufWidth, LBufHeight);
|
||||
|
||||
|
||||
ClearScreen(true);
|
||||
coordScreen.Y = 0;
|
||||
coordScreen.X = 0;
|
||||
DWORD cCharsWritten = 0;
|
||||
|
||||
int BytesWritten = 0;
|
||||
DWORD cAttrWritten = 0;
|
||||
for (size_t i = 0; i < Attr.size(); i++)
|
||||
{
|
||||
if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten))
|
||||
SLog += StringFromFormat("WriteConsoleOutputCharacter error");
|
||||
if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten))
|
||||
SLog += StringFromFormat("WriteConsoleOutputAttribute error");
|
||||
|
||||
BytesWritten += cAttrWritten;
|
||||
coordScreen = GetCoordinates(BytesWritten, LBufWidth);
|
||||
}
|
||||
|
||||
const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X;
|
||||
COORD Coo = GetCoordinates(OldCursor, LBufWidth);
|
||||
SetConsoleCursorPosition(hConsole, Coo);
|
||||
|
||||
if (SLog.length() > 0) Log(LogTypes::LNOTICE, SLog.c_str());
|
||||
|
||||
// Resize the window too
|
||||
if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (hThread == NULL)
|
||||
WriteToConsole(Level, Text, strlen(Text));
|
||||
else
|
||||
SendToThread(Level, Text);
|
||||
#else
|
||||
char ColorAttr[16] = "";
|
||||
char ResetAttr[16] = "";
|
||||
|
||||
if (bUseColor)
|
||||
{
|
||||
strcpy(ResetAttr, "\033[0m");
|
||||
switch (Level)
|
||||
{
|
||||
case NOTICE_LEVEL: // light green
|
||||
strcpy(ColorAttr, "\033[92m");
|
||||
break;
|
||||
case ERROR_LEVEL: // light red
|
||||
strcpy(ColorAttr, "\033[91m");
|
||||
break;
|
||||
case WARNING_LEVEL: // light yellow
|
||||
strcpy(ColorAttr, "\033[93m");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr);
|
||||
#endif
|
||||
}
|
||||
// Clear console screen
|
||||
void ConsoleListener::ClearScreen(bool Cursor)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
COORD coordScreen = { 0, 0 };
|
||||
DWORD cCharsWritten;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
DWORD dwConSize;
|
||||
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
GetConsoleScreenBufferInfo(hConsole, &csbi);
|
||||
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
|
||||
// Write space to the entire console
|
||||
FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
|
||||
GetConsoleScreenBufferInfo(hConsole, &csbi);
|
||||
FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
|
||||
// Reset cursor
|
||||
if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _CONSOLELISTENER_H
|
||||
#define _CONSOLELISTENER_H
|
||||
|
||||
#include "LogManager.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
class ConsoleListener : public LogListener
|
||||
{
|
||||
public:
|
||||
ConsoleListener();
|
||||
~ConsoleListener();
|
||||
|
||||
void Open(bool Hidden = false, int Width = 200, int Height = 100, const char * Name = "DebugConsole (PPSSPP)");
|
||||
void UpdateHandle();
|
||||
void Close();
|
||||
bool IsOpen();
|
||||
void LetterSpace(int Width, int Height);
|
||||
void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst);
|
||||
void PixelSpace(int Left, int Top, int Width, int Height, bool);
|
||||
#ifdef _WIN32
|
||||
COORD GetCoordinates(int BytesRead, int BufferWidth);
|
||||
#endif
|
||||
void Log(LogTypes::LOG_LEVELS, const char *Text);
|
||||
void ClearScreen(bool Cursor = true);
|
||||
|
||||
void Show(bool bShow);
|
||||
bool Hidden() const { return bHidden; }
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
HWND GetHwnd(void);
|
||||
HANDLE hConsole;
|
||||
|
||||
static unsigned int WINAPI RunThread(void *lpParam);
|
||||
void LogWriterThread();
|
||||
void SendToThread(LogTypes::LOG_LEVELS Level, const char *Text);
|
||||
void WriteToConsole(LogTypes::LOG_LEVELS Level, const char *Text, size_t Len);
|
||||
|
||||
static int refCount;
|
||||
static HANDLE hThread;
|
||||
static HANDLE hTriggerEvent;
|
||||
static CRITICAL_SECTION criticalSection;
|
||||
|
||||
static char *logPending;
|
||||
static volatile u32 logPendingReadPos;
|
||||
static volatile u32 logPendingWritePos;
|
||||
#endif
|
||||
bool bHidden;
|
||||
bool bUseColor;
|
||||
};
|
||||
|
||||
#endif // _CONSOLELISTENER_H
|
|
@ -0,0 +1,143 @@
|
|||
/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HEADER_AES_H
|
||||
#define HEADER_AES_H
|
||||
|
||||
// #include <openssl/opensslconf.h>
|
||||
|
||||
#ifdef OPENSSL_NO_AES
|
||||
#error AES is disabled.
|
||||
#endif
|
||||
|
||||
#define AES_ENCRYPT 1
|
||||
#define AES_DECRYPT 0
|
||||
|
||||
/* Because array size can't be a const in C, the following two are macros.
|
||||
Both sizes are in bytes. */
|
||||
#define AES_MAXNR 14
|
||||
#define AES_BLOCK_SIZE 16
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This should be a hidden type, but EVP requires that the size be known */
|
||||
struct aes_key_st
|
||||
{
|
||||
#ifdef AES_LONG
|
||||
unsigned long rd_key[4 * (AES_MAXNR + 1)];
|
||||
#else
|
||||
unsigned int rd_key[4 * (AES_MAXNR + 1)];
|
||||
#endif
|
||||
int rounds;
|
||||
};
|
||||
typedef struct aes_key_st AES_KEY;
|
||||
|
||||
const char* AES_options(void);
|
||||
|
||||
int AES_set_encrypt_key(const unsigned char* userKey, const int bits,
|
||||
AES_KEY* key);
|
||||
int AES_set_decrypt_key(const unsigned char* userKey, const int bits,
|
||||
AES_KEY* key);
|
||||
|
||||
void AES_encrypt1(const unsigned char* in, unsigned char* out,
|
||||
const AES_KEY* key);
|
||||
void AES_decrypt1(const unsigned char* in, unsigned char* out,
|
||||
const AES_KEY* key);
|
||||
|
||||
void AES_ecb_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const AES_KEY* key, const int enc);
|
||||
void AES_cbc_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const unsigned long length, const AES_KEY* key,
|
||||
unsigned char* ivec, const int enc);
|
||||
void AES_cfb128_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const unsigned long length, const AES_KEY* key,
|
||||
unsigned char* ivec, int* num, const int enc);
|
||||
void AES_cfb1_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const unsigned long length, const AES_KEY* key,
|
||||
unsigned char* ivec, int* num, const int enc);
|
||||
void AES_cfb8_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const unsigned long length, const AES_KEY* key,
|
||||
unsigned char* ivec, int* num, const int enc);
|
||||
void AES_cfbr_encrypt_block(const unsigned char* in, unsigned char* out,
|
||||
const int nbits, const AES_KEY* key,
|
||||
unsigned char* ivec, const int enc);
|
||||
void AES_ofb128_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const unsigned long length, const AES_KEY* key,
|
||||
unsigned char* ivec, int* num);
|
||||
|
||||
|
||||
void AES_ctr128_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const unsigned long length, const AES_KEY * key,
|
||||
unsigned char ivec[AES_BLOCK_SIZE],
|
||||
unsigned char ecount_buf[AES_BLOCK_SIZE],
|
||||
unsigned int* num);
|
||||
|
||||
/* For IGE, see also http://www.links.org/files/openssl-ige.pdf
|
||||
NB: the IV is _two_ blocks long */
|
||||
void AES_ige_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const unsigned long length, const AES_KEY* key,
|
||||
unsigned char* ivec, const int enc);
|
||||
|
||||
|
||||
/* NB: the IV is _four_ blocks long */
|
||||
void AES_bi_ige_encrypt(const unsigned char* in, unsigned char* out,
|
||||
const unsigned long length, const AES_KEY* key,
|
||||
const AES_KEY* key2, const unsigned char* ivec,
|
||||
const int enc);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !HEADER_AES_H */
|
|
@ -0,0 +1,131 @@
|
|||
/* crypto/aes/aes_cbc.c -*- mode:C; c-file-style: "eay" -*- */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AES_DEBUG
|
||||
# ifndef NDEBUG
|
||||
# define NDEBUG
|
||||
# endif
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#include "aes.h"
|
||||
#include "aes_locl.h"
|
||||
|
||||
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const unsigned long length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc) {
|
||||
|
||||
unsigned long n;
|
||||
unsigned long len = length;
|
||||
unsigned char tmp[AES_BLOCK_SIZE];
|
||||
const unsigned char *iv = ivec;
|
||||
|
||||
assert(in && out && key && ivec);
|
||||
assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
|
||||
|
||||
if (AES_ENCRYPT == enc) {
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
for(n=0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] = in[n] ^ iv[n];
|
||||
AES_encrypt1(out, out, key);
|
||||
iv = out;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
if (len) {
|
||||
for(n=0; n < len; ++n)
|
||||
out[n] = in[n] ^ iv[n];
|
||||
for(n=len; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] = iv[n];
|
||||
AES_encrypt1(out, out, key);
|
||||
iv = out;
|
||||
}
|
||||
memcpy(ivec,iv,AES_BLOCK_SIZE);
|
||||
} else if (in != out) {
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
AES_decrypt1(in, out, key);
|
||||
for(n=0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] ^= iv[n];
|
||||
iv = in;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
if (len) {
|
||||
AES_decrypt1(in,tmp,key);
|
||||
for(n=0; n < len; ++n)
|
||||
out[n] = tmp[n] ^ iv[n];
|
||||
iv = in;
|
||||
}
|
||||
memcpy(ivec,iv,AES_BLOCK_SIZE);
|
||||
} else {
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
AES_decrypt1(in, out, key);
|
||||
for(n=0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] ^= ivec[n];
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
if (len) {
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
AES_decrypt1(tmp, out, key);
|
||||
for(n=0; n < len; ++n)
|
||||
out[n] ^= ivec[n];
|
||||
for(n=len; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] = tmp[n];
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
|||
/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HEADER_AES_LOCL_H
|
||||
#define HEADER_AES_LOCL_H
|
||||
|
||||
|
||||
#ifdef OPENSSL_NO_AES
|
||||
#error AES is disabled.
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined (_MSC_VER) && (defined (_M_IX86) || defined (_M_AMD64) || defined (_M_X64))
|
||||
# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
|
||||
# define GETU32(p) SWAP(*((u32*)(p)))
|
||||
# define PUTU32(ct, st) {*((u32*)(ct)) = SWAP((st));}
|
||||
#else
|
||||
# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
|
||||
# define PUTU32(ct, st) {(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st);}
|
||||
#endif
|
||||
|
||||
#ifdef AES_LONG
|
||||
typedef unsigned long u32;
|
||||
#else
|
||||
typedef unsigned int u32;
|
||||
#endif
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
|
||||
#define MAXKC (256 / 32)
|
||||
#define MAXKB (256 / 8)
|
||||
#define MAXNR 14
|
||||
|
||||
/* This controls loop-unrolling in aes_core.c */
|
||||
#undef FULL_UNROLL
|
||||
|
||||
#endif /* !HEADER_AES_LOCL_H */
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
// Licensed under the terms of the GNU GPL, version 2
|
||||
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "../Common.h"
|
||||
#include "tools.h"
|
||||
|
||||
/*static void bn_print(char *name, u8 *a, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
printf("%s = ", name);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
printf("%02x", a[i]);
|
||||
|
||||
printf("\n");
|
||||
}*/
|
||||
|
||||
static void bn_zero(u8 *d, u32 n)
|
||||
{
|
||||
memset(d, 0, n);
|
||||
}
|
||||
|
||||
static void bn_copy(u8 *d, u8 *a, u32 n)
|
||||
{
|
||||
memcpy(d, a, n);
|
||||
}
|
||||
|
||||
int bn_compare(u8 *a, u8 *b, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (a[i] < b[i])
|
||||
return -1;
|
||||
if (a[i] > b[i])
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bn_sub_modulus(u8 *a, u8 *N, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
u32 dig;
|
||||
u8 c;
|
||||
|
||||
c = 0;
|
||||
for (i = n - 1; i < n; i--) {
|
||||
dig = N[i] + c;
|
||||
c = (a[i] < dig);
|
||||
a[i] -= dig;
|
||||
}
|
||||
}
|
||||
|
||||
void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
u32 dig;
|
||||
u8 c;
|
||||
|
||||
c = 0;
|
||||
for (i = n - 1; i < n; i--) {
|
||||
dig = a[i] + b[i] + c;
|
||||
c = (dig >= 0x100);
|
||||
d[i] = dig;
|
||||
}
|
||||
|
||||
if (c)
|
||||
bn_sub_modulus(d, N, n);
|
||||
|
||||
if (bn_compare(d, N, n) >= 0)
|
||||
bn_sub_modulus(d, N, n);
|
||||
}
|
||||
|
||||
void bn_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
u8 mask;
|
||||
|
||||
bn_zero(d, n);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
for (mask = 0x80; mask != 0; mask >>= 1) {
|
||||
bn_add(d, d, d, N, n);
|
||||
if ((a[i] & mask) != 0)
|
||||
bn_add(d, d, b, N, n);
|
||||
}
|
||||
}
|
||||
|
||||
void bn_exp(u8 *d, u8 *a, u8 *N, u32 n, u8 *e, u32 en)
|
||||
{
|
||||
u8 t[512];
|
||||
u32 i;
|
||||
u8 mask;
|
||||
|
||||
bn_zero(d, n);
|
||||
d[n-1] = 1;
|
||||
for (i = 0; i < en; i++)
|
||||
for (mask = 0x80; mask != 0; mask >>= 1) {
|
||||
bn_mul(t, d, d, N, n);
|
||||
if ((e[i] & mask) != 0)
|
||||
bn_mul(d, t, a, N, n);
|
||||
else
|
||||
bn_copy(d, t, n);
|
||||
}
|
||||
}
|
||||
|
||||
// only for prime N -- stupid but lazy, see if I care
|
||||
void bn_inv(u8 *d, u8 *a, u8 *N, u32 n)
|
||||
{
|
||||
u8 t[512], s[512];
|
||||
|
||||
bn_copy(t, N, n);
|
||||
bn_zero(s, n);
|
||||
s[n-1] = 2;
|
||||
bn_sub_modulus(t, s, n);
|
||||
bn_exp(d, a, N, n, t, n);
|
||||
}
|
|
@ -0,0 +1,400 @@
|
|||
// Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
// Licensed under the terms of the GNU GPL, version 2
|
||||
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../Common.h"
|
||||
#include "tools.h"
|
||||
// y**2 + x*y = x**3 + x + b
|
||||
/*
|
||||
static u8 ec_b[30] =
|
||||
{0x00,0x66,0x64,0x7e,0xde,0x6c,0x33,0x2c,0x7f,0x8c,0x09,0x23,0xbb,0x58,0x21
|
||||
,0x3b,0x33,0x3b,0x20,0xe9,0xce,0x42,0x81,0xfe,0x11,0x5f,0x7d,0x8f,0x90,0xad};
|
||||
*/
|
||||
|
||||
// order of the addition group of points
|
||||
static u8 ec_N[30] =
|
||||
{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
,0x13,0xe9,0x74,0xe7,0x2f,0x8a,0x69,0x22,0x03,0x1d,0x26,0x03,0xcf,0xe0,0xd7};
|
||||
|
||||
// base point
|
||||
static u8 ec_G[60] =
|
||||
{0x00,0xfa,0xc9,0xdf,0xcb,0xac,0x83,0x13,0xbb,0x21,0x39,0xf1,0xbb,0x75,0x5f
|
||||
,0xef,0x65,0xbc,0x39,0x1f,0x8b,0x36,0xf8,0xf8,0xeb,0x73,0x71,0xfd,0x55,0x8b
|
||||
,0x01,0x00,0x6a,0x08,0xa4,0x19,0x03,0x35,0x06,0x78,0xe5,0x85,0x28,0xbe,0xbf
|
||||
,0x8a,0x0b,0xef,0xf8,0x67,0xa7,0xca,0x36,0x71,0x6f,0x7e,0x01,0xf8,0x10,0x52};
|
||||
|
||||
/*static void elt_print(char *name, u8 *a)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
printf("%s = ", name);
|
||||
|
||||
for (i = 0; i < 30; i++)
|
||||
printf("%02x", a[i]);
|
||||
|
||||
printf("\n");
|
||||
}*/
|
||||
|
||||
static void elt_copy(u8 *d, u8 *a)
|
||||
{
|
||||
memcpy(d, a, 30);
|
||||
}
|
||||
|
||||
static void elt_zero(u8 *d)
|
||||
{
|
||||
memset(d, 0, 30);
|
||||
}
|
||||
|
||||
static int elt_is_zero(u8 *d)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < 30; i++)
|
||||
if (d[i] != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void elt_add(u8 *d, u8 *a, u8 *b)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < 30; i++)
|
||||
d[i] = a[i] ^ b[i];
|
||||
}
|
||||
|
||||
static void elt_mul_x(u8 *d, u8 *a)
|
||||
{
|
||||
u8 carry, x, y;
|
||||
u32 i;
|
||||
|
||||
carry = a[0] & 1;
|
||||
|
||||
x = 0;
|
||||
for (i = 0; i < 29; i++) {
|
||||
y = a[i + 1];
|
||||
d[i] = x ^ (y >> 7);
|
||||
x = y << 1;
|
||||
}
|
||||
d[29] = x ^ carry;
|
||||
|
||||
d[20] ^= carry << 2;
|
||||
}
|
||||
|
||||
static void elt_mul(u8 *d, u8 *a, u8 *b)
|
||||
{
|
||||
u32 i, n;
|
||||
u8 mask;
|
||||
|
||||
elt_zero(d);
|
||||
|
||||
i = 0;
|
||||
mask = 1;
|
||||
for (n = 0; n < 233; n++) {
|
||||
elt_mul_x(d, d);
|
||||
|
||||
if ((a[i] & mask) != 0)
|
||||
elt_add(d, d, b);
|
||||
|
||||
mask >>= 1;
|
||||
if (mask == 0) {
|
||||
mask = 0x80;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const u8 square[16] =
|
||||
{0x00,0x01,0x04,0x05,0x10,0x11,0x14,0x15,0x40,0x41,0x44,0x45,0x50,0x51,0x54,0x55};
|
||||
|
||||
static void elt_square_to_wide(u8 *d, u8 *a)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < 30; i++) {
|
||||
d[2*i] = square[a[i] >> 4];
|
||||
d[2*i + 1] = square[a[i] & 15];
|
||||
}
|
||||
}
|
||||
|
||||
static void wide_reduce(u8 *d)
|
||||
{
|
||||
u32 i;
|
||||
u8 x;
|
||||
|
||||
for (i = 0; i < 30; i++) {
|
||||
x = d[i];
|
||||
|
||||
d[i + 19] ^= x >> 7;
|
||||
d[i + 20] ^= x << 1;
|
||||
|
||||
d[i + 29] ^= x >> 1;
|
||||
d[i + 30] ^= x << 7;
|
||||
}
|
||||
|
||||
x = d[30] & ~1;
|
||||
|
||||
d[49] ^= x >> 7;
|
||||
d[50] ^= x << 1;
|
||||
|
||||
d[59] ^= x >> 1;
|
||||
|
||||
d[30] &= 1;
|
||||
}
|
||||
|
||||
static void elt_square(u8 *d, u8 *a)
|
||||
{
|
||||
u8 wide[60];
|
||||
|
||||
elt_square_to_wide(wide, a);
|
||||
wide_reduce(wide);
|
||||
|
||||
elt_copy(d, wide + 30);
|
||||
}
|
||||
|
||||
static void itoh_tsujii(u8 *d, u8 *a, u8 *b, u32 j)
|
||||
{
|
||||
u8 t[30];
|
||||
|
||||
elt_copy(t, a);
|
||||
while (j--) {
|
||||
elt_square(d, t);
|
||||
elt_copy(t, d);
|
||||
}
|
||||
|
||||
elt_mul(d, t, b);
|
||||
}
|
||||
|
||||
static void elt_inv(u8 *d, u8 *a)
|
||||
{
|
||||
u8 t[30];
|
||||
u8 s[30];
|
||||
|
||||
itoh_tsujii(t, a, a, 1);
|
||||
itoh_tsujii(s, t, a, 1);
|
||||
itoh_tsujii(t, s, s, 3);
|
||||
itoh_tsujii(s, t, a, 1);
|
||||
itoh_tsujii(t, s, s, 7);
|
||||
itoh_tsujii(s, t, t, 14);
|
||||
itoh_tsujii(t, s, a, 1);
|
||||
itoh_tsujii(s, t, t, 29);
|
||||
itoh_tsujii(t, s, s, 58);
|
||||
itoh_tsujii(s, t, t, 116);
|
||||
elt_square(d, s);
|
||||
}
|
||||
|
||||
/*static int point_is_on_curve(u8 *p)
|
||||
{
|
||||
u8 s[30], t[30];
|
||||
u8 *x, *y;
|
||||
|
||||
x = p;
|
||||
y = p + 30;
|
||||
|
||||
elt_square(t, x);
|
||||
elt_mul(s, t, x);
|
||||
|
||||
elt_add(s, s, t);
|
||||
|
||||
elt_square(t, y);
|
||||
elt_add(s, s, t);
|
||||
|
||||
elt_mul(t, x, y);
|
||||
elt_add(s, s, t);
|
||||
|
||||
elt_add(s, s, ec_b);
|
||||
|
||||
return elt_is_zero(s);
|
||||
}
|
||||
*/
|
||||
static int point_is_zero(u8 *p)
|
||||
{
|
||||
return elt_is_zero(p) && elt_is_zero(p + 30);
|
||||
}
|
||||
|
||||
static void point_double(u8 *r, u8 *p)
|
||||
{
|
||||
u8 s[30], t[30];
|
||||
u8 *px, *py, *rx, *ry;
|
||||
|
||||
px = p;
|
||||
py = p + 30;
|
||||
rx = r;
|
||||
ry = r + 30;
|
||||
|
||||
if (elt_is_zero(px)) {
|
||||
elt_zero(rx);
|
||||
elt_zero(ry);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
elt_inv(t, px);
|
||||
elt_mul(s, py, t);
|
||||
elt_add(s, s, px);
|
||||
|
||||
elt_square(t, px);
|
||||
|
||||
elt_square(rx, s);
|
||||
elt_add(rx, rx, s);
|
||||
rx[29] ^= 1;
|
||||
|
||||
elt_mul(ry, s, rx);
|
||||
elt_add(ry, ry, rx);
|
||||
elt_add(ry, ry, t);
|
||||
}
|
||||
|
||||
static void point_add(u8 *r, u8 *p, u8 *q)
|
||||
{
|
||||
u8 s[30], t[30], u[30];
|
||||
u8 *px, *py, *qx, *qy, *rx, *ry;
|
||||
|
||||
px = p;
|
||||
py = p + 30;
|
||||
qx = q;
|
||||
qy = q + 30;
|
||||
rx = r;
|
||||
ry = r + 30;
|
||||
|
||||
if (point_is_zero(p)) {
|
||||
elt_copy(rx, qx);
|
||||
elt_copy(ry, qy);
|
||||
return;
|
||||
}
|
||||
|
||||
if (point_is_zero(q)) {
|
||||
elt_copy(rx, px);
|
||||
elt_copy(ry, py);
|
||||
return;
|
||||
}
|
||||
|
||||
elt_add(u, px, qx);
|
||||
|
||||
if (elt_is_zero(u)) {
|
||||
elt_add(u, py, qy);
|
||||
if (elt_is_zero(u))
|
||||
point_double(r, p);
|
||||
else {
|
||||
elt_zero(rx);
|
||||
elt_zero(ry);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
elt_inv(t, u);
|
||||
elt_add(u, py, qy);
|
||||
elt_mul(s, t, u);
|
||||
|
||||
elt_square(t, s);
|
||||
elt_add(t, t, s);
|
||||
elt_add(t, t, qx);
|
||||
t[29] ^= 1;
|
||||
|
||||
elt_mul(u, s, t);
|
||||
elt_add(s, u, py);
|
||||
elt_add(rx, t, px);
|
||||
elt_add(ry, s, rx);
|
||||
}
|
||||
|
||||
static void point_mul(u8 *d, u8 *a, u8 *b) // a is bignum
|
||||
{
|
||||
u32 i;
|
||||
u8 mask;
|
||||
|
||||
elt_zero(d);
|
||||
elt_zero(d + 30);
|
||||
|
||||
for (i = 0; i < 30; i++)
|
||||
for (mask = 0x80; mask != 0; mask >>= 1) {
|
||||
point_double(d, d);
|
||||
if ((a[i] & mask) != 0)
|
||||
point_add(d, d, b);
|
||||
}
|
||||
}
|
||||
|
||||
void silly_random(u8 * rndArea, u8 count)
|
||||
{
|
||||
u16 i;
|
||||
srand((unsigned) (time(NULL)));
|
||||
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
rndArea[i]=rand();
|
||||
}
|
||||
}
|
||||
|
||||
void generate_ecdsa(u8 *R, u8 *S, u8 *k, u8 *hash)
|
||||
{
|
||||
u8 e[30];
|
||||
u8 kk[30];
|
||||
u8 m[30];
|
||||
u8 minv[30];
|
||||
u8 mG[60];
|
||||
//FILE *fp;
|
||||
|
||||
elt_zero(e);
|
||||
memcpy(e + 10, hash, 20);
|
||||
|
||||
//Changing random number generator to a lame one...
|
||||
silly_random(m, sizeof(m));
|
||||
//fp = fopen("/dev/random", "rb");
|
||||
//if (fread(m, sizeof m, 1, fp) != 1)
|
||||
// fatal("reading random");
|
||||
//fclose(fp);
|
||||
m[0] = 0;
|
||||
|
||||
// R = (mG).x
|
||||
|
||||
point_mul(mG, m, ec_G);
|
||||
elt_copy(R, mG);
|
||||
if (bn_compare(R, ec_N, 30) >= 0)
|
||||
bn_sub_modulus(R, ec_N, 30);
|
||||
|
||||
// S = m**-1*(e + Rk) (mod N)
|
||||
|
||||
elt_copy(kk, k);
|
||||
if (bn_compare(kk, ec_N, 30) >= 0)
|
||||
bn_sub_modulus(kk, ec_N, 30);
|
||||
bn_mul(S, R, kk, ec_N, 30);
|
||||
bn_add(kk, S, e, ec_N, 30);
|
||||
bn_inv(minv, m, ec_N, 30);
|
||||
bn_mul(S, minv, kk, ec_N, 30);
|
||||
}
|
||||
|
||||
int check_ecdsa(u8 *Q, u8 *R, u8 *S, u8 *hash)
|
||||
{
|
||||
u8 Sinv[30];
|
||||
u8 e[30];
|
||||
u8 w1[30], w2[30];
|
||||
u8 r1[60], r2[60];
|
||||
|
||||
bn_inv(Sinv, S, ec_N, 30);
|
||||
|
||||
elt_zero(e);
|
||||
memcpy(e + 10, hash, 20);
|
||||
|
||||
bn_mul(w1, e, Sinv, ec_N, 30);
|
||||
bn_mul(w2, R, Sinv, ec_N, 30);
|
||||
|
||||
point_mul(r1, w1, ec_G);
|
||||
point_mul(r2, w2, Q);
|
||||
|
||||
point_add(r1, r1, r2);
|
||||
|
||||
if (bn_compare(r1, ec_N, 30) >= 0)
|
||||
bn_sub_modulus(r1, ec_N, 30);
|
||||
|
||||
return (bn_compare(r1, R, 30) == 0);
|
||||
}
|
||||
|
||||
void ec_priv_to_pub(u8 *k, u8 *Q)
|
||||
{
|
||||
point_mul(Q, k, ec_G);
|
||||
}
|
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2006-2009, Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Joined copyright on original XySSL code with: Christophe Devine
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*
|
||||
* The MD5 algorithm was designed by Ron Rivest in 1991.
|
||||
*
|
||||
* http://www.ietf.org/rfc/rfc1321.txt
|
||||
*/
|
||||
|
||||
//#include "polarssl/config.h"
|
||||
|
||||
#if defined(POLARSSL_MD5_C)
|
||||
|
||||
#include "polarssl/md5.h"
|
||||
#else
|
||||
#include "md5.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* 32-bit integer manipulation macros (little endian)
|
||||
*/
|
||||
#ifndef GET_ULONG_LE
|
||||
#define GET_ULONG_LE(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (unsigned long) (b)[(i) ] ) \
|
||||
| ( (unsigned long) (b)[(i) + 1] << 8 ) \
|
||||
| ( (unsigned long) (b)[(i) + 2] << 16 ) \
|
||||
| ( (unsigned long) (b)[(i) + 3] << 24 ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PUT_ULONG_LE
|
||||
#define PUT_ULONG_LE(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (unsigned char) ( (n) ); \
|
||||
(b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
|
||||
(b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
|
||||
(b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MD5 context setup
|
||||
*/
|
||||
void md5_starts( md5_context *ctx )
|
||||
{
|
||||
ctx->total[0] = 0;
|
||||
ctx->total[1] = 0;
|
||||
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
static void md5_process( md5_context *ctx, unsigned char data[64] )
|
||||
{
|
||||
unsigned long X[16], A, B, C, D;
|
||||
|
||||
GET_ULONG_LE( X[ 0], data, 0 );
|
||||
GET_ULONG_LE( X[ 1], data, 4 );
|
||||
GET_ULONG_LE( X[ 2], data, 8 );
|
||||
GET_ULONG_LE( X[ 3], data, 12 );
|
||||
GET_ULONG_LE( X[ 4], data, 16 );
|
||||
GET_ULONG_LE( X[ 5], data, 20 );
|
||||
GET_ULONG_LE( X[ 6], data, 24 );
|
||||
GET_ULONG_LE( X[ 7], data, 28 );
|
||||
GET_ULONG_LE( X[ 8], data, 32 );
|
||||
GET_ULONG_LE( X[ 9], data, 36 );
|
||||
GET_ULONG_LE( X[10], data, 40 );
|
||||
GET_ULONG_LE( X[11], data, 44 );
|
||||
GET_ULONG_LE( X[12], data, 48 );
|
||||
GET_ULONG_LE( X[13], data, 52 );
|
||||
GET_ULONG_LE( X[14], data, 56 );
|
||||
GET_ULONG_LE( X[15], data, 60 );
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) \
|
||||
{ \
|
||||
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P( A, B, C, D, 0, 7, 0xD76AA478 );
|
||||
P( D, A, B, C, 1, 12, 0xE8C7B756 );
|
||||
P( C, D, A, B, 2, 17, 0x242070DB );
|
||||
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
|
||||
P( A, B, C, D, 4, 7, 0xF57C0FAF );
|
||||
P( D, A, B, C, 5, 12, 0x4787C62A );
|
||||
P( C, D, A, B, 6, 17, 0xA8304613 );
|
||||
P( B, C, D, A, 7, 22, 0xFD469501 );
|
||||
P( A, B, C, D, 8, 7, 0x698098D8 );
|
||||
P( D, A, B, C, 9, 12, 0x8B44F7AF );
|
||||
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
|
||||
P( B, C, D, A, 11, 22, 0x895CD7BE );
|
||||
P( A, B, C, D, 12, 7, 0x6B901122 );
|
||||
P( D, A, B, C, 13, 12, 0xFD987193 );
|
||||
P( C, D, A, B, 14, 17, 0xA679438E );
|
||||
P( B, C, D, A, 15, 22, 0x49B40821 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P( A, B, C, D, 1, 5, 0xF61E2562 );
|
||||
P( D, A, B, C, 6, 9, 0xC040B340 );
|
||||
P( C, D, A, B, 11, 14, 0x265E5A51 );
|
||||
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
|
||||
P( A, B, C, D, 5, 5, 0xD62F105D );
|
||||
P( D, A, B, C, 10, 9, 0x02441453 );
|
||||
P( C, D, A, B, 15, 14, 0xD8A1E681 );
|
||||
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
|
||||
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
|
||||
P( D, A, B, C, 14, 9, 0xC33707D6 );
|
||||
P( C, D, A, B, 3, 14, 0xF4D50D87 );
|
||||
P( B, C, D, A, 8, 20, 0x455A14ED );
|
||||
P( A, B, C, D, 13, 5, 0xA9E3E905 );
|
||||
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
|
||||
P( C, D, A, B, 7, 14, 0x676F02D9 );
|
||||
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P( A, B, C, D, 5, 4, 0xFFFA3942 );
|
||||
P( D, A, B, C, 8, 11, 0x8771F681 );
|
||||
P( C, D, A, B, 11, 16, 0x6D9D6122 );
|
||||
P( B, C, D, A, 14, 23, 0xFDE5380C );
|
||||
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
|
||||
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
|
||||
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
|
||||
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
|
||||
P( A, B, C, D, 13, 4, 0x289B7EC6 );
|
||||
P( D, A, B, C, 0, 11, 0xEAA127FA );
|
||||
P( C, D, A, B, 3, 16, 0xD4EF3085 );
|
||||
P( B, C, D, A, 6, 23, 0x04881D05 );
|
||||
P( A, B, C, D, 9, 4, 0xD9D4D039 );
|
||||
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
|
||||
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
|
||||
P( B, C, D, A, 2, 23, 0xC4AC5665 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P( A, B, C, D, 0, 6, 0xF4292244 );
|
||||
P( D, A, B, C, 7, 10, 0x432AFF97 );
|
||||
P( C, D, A, B, 14, 15, 0xAB9423A7 );
|
||||
P( B, C, D, A, 5, 21, 0xFC93A039 );
|
||||
P( A, B, C, D, 12, 6, 0x655B59C3 );
|
||||
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
|
||||
P( C, D, A, B, 10, 15, 0xFFEFF47D );
|
||||
P( B, C, D, A, 1, 21, 0x85845DD1 );
|
||||
P( A, B, C, D, 8, 6, 0x6FA87E4F );
|
||||
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
|
||||
P( C, D, A, B, 6, 15, 0xA3014314 );
|
||||
P( B, C, D, A, 13, 21, 0x4E0811A1 );
|
||||
P( A, B, C, D, 4, 6, 0xF7537E82 );
|
||||
P( D, A, B, C, 11, 10, 0xBD3AF235 );
|
||||
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
|
||||
P( B, C, D, A, 9, 21, 0xEB86D391 );
|
||||
|
||||
#undef F
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 process buffer
|
||||
*/
|
||||
void md5_update( md5_context *ctx, unsigned char *input, int ilen )
|
||||
{
|
||||
int fill;
|
||||
unsigned long left;
|
||||
|
||||
if( ilen <= 0 )
|
||||
return;
|
||||
|
||||
left = ctx->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->total[0] += ilen;
|
||||
ctx->total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if( ctx->total[0] < (unsigned long) ilen )
|
||||
ctx->total[1]++;
|
||||
|
||||
if( left && ilen >= fill )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, fill );
|
||||
md5_process( ctx, ctx->buffer );
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while( ilen >= 64 )
|
||||
{
|
||||
md5_process( ctx, input );
|
||||
input += 64;
|
||||
ilen -= 64;
|
||||
}
|
||||
|
||||
if( ilen > 0 )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, ilen );
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char md5_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* MD5 final digest
|
||||
*/
|
||||
void md5_finish( md5_context *ctx, unsigned char output[16] )
|
||||
{
|
||||
unsigned long last, padn;
|
||||
unsigned long high, low;
|
||||
unsigned char msglen[8];
|
||||
|
||||
high = ( ctx->total[0] >> 29 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_ULONG_LE( low, msglen, 0 );
|
||||
PUT_ULONG_LE( high, msglen, 4 );
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
md5_update( ctx, (unsigned char *) md5_padding, padn );
|
||||
md5_update( ctx, msglen, 8 );
|
||||
|
||||
PUT_ULONG_LE( ctx->state[0], output, 0 );
|
||||
PUT_ULONG_LE( ctx->state[1], output, 4 );
|
||||
PUT_ULONG_LE( ctx->state[2], output, 8 );
|
||||
PUT_ULONG_LE( ctx->state[3], output, 12 );
|
||||
}
|
||||
|
||||
/*
|
||||
* output = MD5( input buffer )
|
||||
*/
|
||||
void md5( unsigned char *input, int ilen, unsigned char output[16] )
|
||||
{
|
||||
md5_context ctx;
|
||||
|
||||
md5_starts( &ctx );
|
||||
md5_update( &ctx, input, ilen );
|
||||
md5_finish( &ctx, output );
|
||||
|
||||
memset( &ctx, 0, sizeof( md5_context ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* output = MD5( file contents )
|
||||
*/
|
||||
int md5_file( char *path, unsigned char output[16] )
|
||||
{
|
||||
FILE *f;
|
||||
size_t n;
|
||||
md5_context ctx;
|
||||
unsigned char buf[1024];
|
||||
|
||||
if( ( f = fopen( path, "rb" ) ) == NULL )
|
||||
return( 1 );
|
||||
|
||||
md5_starts( &ctx );
|
||||
|
||||
while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
|
||||
md5_update( &ctx, buf, (int) n );
|
||||
|
||||
md5_finish( &ctx, output );
|
||||
|
||||
memset( &ctx, 0, sizeof( md5_context ) );
|
||||
|
||||
if( ferror( f ) != 0 )
|
||||
{
|
||||
fclose( f );
|
||||
return( 2 );
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 HMAC context setup
|
||||
*/
|
||||
void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen )
|
||||
{
|
||||
int i;
|
||||
unsigned char sum[16];
|
||||
|
||||
if( keylen > 64 )
|
||||
{
|
||||
md5( key, keylen, sum );
|
||||
keylen = 16;
|
||||
key = sum;
|
||||
}
|
||||
|
||||
memset( ctx->ipad, 0x36, 64 );
|
||||
memset( ctx->opad, 0x5C, 64 );
|
||||
|
||||
for( i = 0; i < keylen; i++ )
|
||||
{
|
||||
ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
|
||||
ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
|
||||
}
|
||||
|
||||
md5_starts( ctx );
|
||||
md5_update( ctx, ctx->ipad, 64 );
|
||||
|
||||
memset( sum, 0, sizeof( sum ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 HMAC process buffer
|
||||
*/
|
||||
void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen )
|
||||
{
|
||||
md5_update( ctx, input, ilen );
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 HMAC final digest
|
||||
*/
|
||||
void md5_hmac_finish( md5_context *ctx, unsigned char output[16] )
|
||||
{
|
||||
unsigned char tmpbuf[16];
|
||||
|
||||
md5_finish( ctx, tmpbuf );
|
||||
md5_starts( ctx );
|
||||
md5_update( ctx, ctx->opad, 64 );
|
||||
md5_update( ctx, tmpbuf, 16 );
|
||||
md5_finish( ctx, output );
|
||||
|
||||
memset( tmpbuf, 0, sizeof( tmpbuf ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* output = HMAC-MD5( hmac key, input buffer )
|
||||
*/
|
||||
void md5_hmac( unsigned char *key, int keylen, unsigned char *input, int ilen,
|
||||
unsigned char output[16] )
|
||||
{
|
||||
md5_context ctx;
|
||||
|
||||
md5_hmac_starts( &ctx, key, keylen );
|
||||
md5_hmac_update( &ctx, input, ilen );
|
||||
md5_hmac_finish( &ctx, output );
|
||||
|
||||
memset( &ctx, 0, sizeof( md5_context ) );
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_SELF_TEST)
|
||||
/*
|
||||
* RFC 1321 test vectors
|
||||
*/
|
||||
static unsigned char md5_test_buf[7][81] =
|
||||
{
|
||||
{ "" },
|
||||
{ "a" },
|
||||
{ "abc" },
|
||||
{ "message digest" },
|
||||
{ "abcdefghijklmnopqrstuvwxyz" },
|
||||
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
|
||||
{ "12345678901234567890123456789012345678901234567890123456789012" \
|
||||
"345678901234567890" }
|
||||
};
|
||||
|
||||
static const int md5_test_buflen[7] =
|
||||
{
|
||||
0, 1, 3, 14, 26, 62, 80
|
||||
};
|
||||
|
||||
static const unsigned char md5_test_sum[7][16] =
|
||||
{
|
||||
{ 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
|
||||
0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E },
|
||||
{ 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
|
||||
0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 },
|
||||
{ 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
|
||||
0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 },
|
||||
{ 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
|
||||
0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 },
|
||||
{ 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
|
||||
0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B },
|
||||
{ 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
|
||||
0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F },
|
||||
{ 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
|
||||
0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A }
|
||||
};
|
||||
|
||||
/*
|
||||
* RFC 2202 test vectors
|
||||
*/
|
||||
static unsigned char md5_hmac_test_key[7][26] =
|
||||
{
|
||||
{ "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" },
|
||||
{ "Jefe" },
|
||||
{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" },
|
||||
{ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
|
||||
"\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
|
||||
{ "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" },
|
||||
{ "" }, /* 0xAA 80 times */
|
||||
{ "" }
|
||||
};
|
||||
|
||||
static const int md5_hmac_test_keylen[7] =
|
||||
{
|
||||
16, 4, 16, 25, 16, 80, 80
|
||||
};
|
||||
|
||||
static unsigned char md5_hmac_test_buf[7][74] =
|
||||
{
|
||||
{ "Hi There" },
|
||||
{ "what do ya want for nothing?" },
|
||||
{ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
|
||||
{ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
|
||||
{ "Test With Truncation" },
|
||||
{ "Test Using Larger Than Block-Size Key - Hash Key First" },
|
||||
{ "Test Using Larger Than Block-Size Key and Larger"
|
||||
" Than One Block-Size Data" }
|
||||
};
|
||||
|
||||
static const int md5_hmac_test_buflen[7] =
|
||||
{
|
||||
8, 28, 50, 50, 20, 54, 73
|
||||
};
|
||||
|
||||
static const unsigned char md5_hmac_test_sum[7][16] =
|
||||
{
|
||||
{ 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C,
|
||||
0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D },
|
||||
{ 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03,
|
||||
0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 },
|
||||
{ 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88,
|
||||
0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 },
|
||||
{ 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA,
|
||||
0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 },
|
||||
{ 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00,
|
||||
0xF9, 0xBA, 0xB9, 0x95 },
|
||||
{ 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F,
|
||||
0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD },
|
||||
{ 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE,
|
||||
0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E }
|
||||
};
|
||||
|
||||
/*
|
||||
* Checkup routine
|
||||
*/
|
||||
int md5_self_test( int verbose )
|
||||
{
|
||||
int i, buflen;
|
||||
unsigned char buf[1024];
|
||||
unsigned char md5sum[16];
|
||||
md5_context ctx;
|
||||
|
||||
for( i = 0; i < 7; i++ )
|
||||
{
|
||||
if( verbose != 0 )
|
||||
printf( " MD5 test #%d: ", i + 1 );
|
||||
|
||||
md5( md5_test_buf[i], md5_test_buflen[i], md5sum );
|
||||
|
||||
if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 )
|
||||
{
|
||||
if( verbose != 0 )
|
||||
printf( "failed\n" );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
if( verbose != 0 )
|
||||
printf( "passed\n" );
|
||||
}
|
||||
|
||||
if( verbose != 0 )
|
||||
printf( "\n" );
|
||||
|
||||
for( i = 0; i < 7; i++ )
|
||||
{
|
||||
if( verbose != 0 )
|
||||
printf( " HMAC-MD5 test #%d: ", i + 1 );
|
||||
|
||||
if( i == 5 || i == 6 )
|
||||
{
|
||||
memset( buf, '\xAA', buflen = 80 );
|
||||
md5_hmac_starts( &ctx, buf, buflen );
|
||||
}
|
||||
else
|
||||
md5_hmac_starts( &ctx, md5_hmac_test_key[i],
|
||||
md5_hmac_test_keylen[i] );
|
||||
|
||||
md5_hmac_update( &ctx, md5_hmac_test_buf[i],
|
||||
md5_hmac_test_buflen[i] );
|
||||
|
||||
md5_hmac_finish( &ctx, md5sum );
|
||||
|
||||
buflen = ( i == 4 ) ? 12 : 16;
|
||||
|
||||
if( memcmp( md5sum, md5_hmac_test_sum[i], buflen ) != 0 )
|
||||
{
|
||||
if( verbose != 0 )
|
||||
printf( "failed\n" );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
if( verbose != 0 )
|
||||
printf( "passed\n" );
|
||||
}
|
||||
|
||||
if( verbose != 0 )
|
||||
printf( "\n" );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* \file md5.h
|
||||
*
|
||||
* Copyright (C) 2006-2009, Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Joined copyright on original XySSL code with: Christophe Devine
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#ifndef POLARSSL_MD5_H
|
||||
#define POLARSSL_MD5_H
|
||||
|
||||
/**
|
||||
* \brief MD5 context structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned long total[2]; /*!< number of bytes processed */
|
||||
unsigned long state[4]; /*!< intermediate digest state */
|
||||
unsigned char buffer[64]; /*!< data block being processed */
|
||||
|
||||
unsigned char ipad[64]; /*!< HMAC: inner padding */
|
||||
unsigned char opad[64]; /*!< HMAC: outer padding */
|
||||
}
|
||||
md5_context;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief MD5 context setup
|
||||
*
|
||||
* \param ctx context to be initialized
|
||||
*/
|
||||
void md5_starts( md5_context *ctx );
|
||||
|
||||
/**
|
||||
* \brief MD5 process buffer
|
||||
*
|
||||
* \param ctx MD5 context
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
*/
|
||||
void md5_update( md5_context *ctx, unsigned char *input, int ilen );
|
||||
|
||||
/**
|
||||
* \brief MD5 final digest
|
||||
*
|
||||
* \param ctx MD5 context
|
||||
* \param output MD5 checksum result
|
||||
*/
|
||||
void md5_finish( md5_context *ctx, unsigned char output[16] );
|
||||
|
||||
/**
|
||||
* \brief Output = MD5( input buffer )
|
||||
*
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* \param output MD5 checksum result
|
||||
*/
|
||||
void md5( unsigned char *input, int ilen, unsigned char output[16] );
|
||||
|
||||
/**
|
||||
* \brief Output = MD5( file contents )
|
||||
*
|
||||
* \param path input file name
|
||||
* \param output MD5 checksum result
|
||||
*
|
||||
* \return 0 if successful, 1 if fopen failed,
|
||||
* or 2 if fread failed
|
||||
*/
|
||||
int md5_file( char *path, unsigned char output[16] );
|
||||
|
||||
/**
|
||||
* \brief MD5 HMAC context setup
|
||||
*
|
||||
* \param ctx HMAC context to be initialized
|
||||
* \param key HMAC secret key
|
||||
* \param keylen length of the HMAC key
|
||||
*/
|
||||
void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen );
|
||||
|
||||
/**
|
||||
* \brief MD5 HMAC process buffer
|
||||
*
|
||||
* \param ctx HMAC context
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
*/
|
||||
void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen );
|
||||
|
||||
/**
|
||||
* \brief MD5 HMAC final digest
|
||||
*
|
||||
* \param ctx HMAC context
|
||||
* \param output MD5 HMAC checksum result
|
||||
*/
|
||||
void md5_hmac_finish( md5_context *ctx, unsigned char output[16] );
|
||||
|
||||
/**
|
||||
* \brief Output = HMAC-MD5( hmac key, input buffer )
|
||||
*
|
||||
* \param key HMAC secret key
|
||||
* \param keylen length of the HMAC key
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* \param output HMAC-MD5 result
|
||||
*/
|
||||
void md5_hmac( unsigned char *key, int keylen,
|
||||
unsigned char *input, int ilen,
|
||||
unsigned char output[16] );
|
||||
|
||||
/**
|
||||
* \brief Checkup routine
|
||||
*
|
||||
* \return 0 if successful, or 1 if the test failed
|
||||
*/
|
||||
int md5_self_test( int verbose );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* md5.h */
|
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
* FIPS-180-1 compliant SHA-1 implementation
|
||||
*
|
||||
* Copyright (C) 2006-2009, Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Joined copyright on original XySSL code with: Christophe Devine
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*
|
||||
* The SHA-1 standard was published by NIST in 1993.
|
||||
*
|
||||
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
|
||||
*/
|
||||
/*
|
||||
#include "polarssl/config.h"
|
||||
|
||||
#if defined(POLARSSL_SHA1_C)
|
||||
|
||||
#include "polarssl/sha1.h"
|
||||
*/
|
||||
#include "sha1.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* 32-bit integer manipulation macros (big endian)
|
||||
*/
|
||||
#ifndef GET_ULONG_BE
|
||||
#define GET_ULONG_BE(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
|
||||
| ( (unsigned long) (b)[(i) + 1] << 16 ) \
|
||||
| ( (unsigned long) (b)[(i) + 2] << 8 ) \
|
||||
| ( (unsigned long) (b)[(i) + 3] ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PUT_ULONG_BE
|
||||
#define PUT_ULONG_BE(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
|
||||
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
|
||||
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
|
||||
(b)[(i) + 3] = (unsigned char) ( (n) ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SHA-1 context setup
|
||||
*/
|
||||
void sha1_starts( sha1_context *ctx )
|
||||
{
|
||||
ctx->total[0] = 0;
|
||||
ctx->total[1] = 0;
|
||||
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
ctx->state[4] = 0xC3D2E1F0;
|
||||
}
|
||||
|
||||
static void sha1_process( sha1_context *ctx, unsigned char data[64] )
|
||||
{
|
||||
unsigned long temp, W[16], A, B, C, D, E;
|
||||
|
||||
GET_ULONG_BE( W[ 0], data, 0 );
|
||||
GET_ULONG_BE( W[ 1], data, 4 );
|
||||
GET_ULONG_BE( W[ 2], data, 8 );
|
||||
GET_ULONG_BE( W[ 3], data, 12 );
|
||||
GET_ULONG_BE( W[ 4], data, 16 );
|
||||
GET_ULONG_BE( W[ 5], data, 20 );
|
||||
GET_ULONG_BE( W[ 6], data, 24 );
|
||||
GET_ULONG_BE( W[ 7], data, 28 );
|
||||
GET_ULONG_BE( W[ 8], data, 32 );
|
||||
GET_ULONG_BE( W[ 9], data, 36 );
|
||||
GET_ULONG_BE( W[10], data, 40 );
|
||||
GET_ULONG_BE( W[11], data, 44 );
|
||||
GET_ULONG_BE( W[12], data, 48 );
|
||||
GET_ULONG_BE( W[13], data, 52 );
|
||||
GET_ULONG_BE( W[14], data, 56 );
|
||||
GET_ULONG_BE( W[15], data, 60 );
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define R(t) \
|
||||
( \
|
||||
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
|
||||
W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \
|
||||
( W[t & 0x0F] = S(temp,1) ) \
|
||||
)
|
||||
|
||||
#define P(a,b,c,d,e,x) \
|
||||
{ \
|
||||
e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
E = ctx->state[4];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
#define K 0x5A827999
|
||||
|
||||
P( A, B, C, D, E, W[0] );
|
||||
P( E, A, B, C, D, W[1] );
|
||||
P( D, E, A, B, C, W[2] );
|
||||
P( C, D, E, A, B, W[3] );
|
||||
P( B, C, D, E, A, W[4] );
|
||||
P( A, B, C, D, E, W[5] );
|
||||
P( E, A, B, C, D, W[6] );
|
||||
P( D, E, A, B, C, W[7] );
|
||||
P( C, D, E, A, B, W[8] );
|
||||
P( B, C, D, E, A, W[9] );
|
||||
P( A, B, C, D, E, W[10] );
|
||||
P( E, A, B, C, D, W[11] );
|
||||
P( D, E, A, B, C, W[12] );
|
||||
P( C, D, E, A, B, W[13] );
|
||||
P( B, C, D, E, A, W[14] );
|
||||
P( A, B, C, D, E, W[15] );
|
||||
P( E, A, B, C, D, R(16) );
|
||||
P( D, E, A, B, C, R(17) );
|
||||
P( C, D, E, A, B, R(18) );
|
||||
P( B, C, D, E, A, R(19) );
|
||||
|
||||
#undef K
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
#define K 0x6ED9EBA1
|
||||
|
||||
P( A, B, C, D, E, R(20) );
|
||||
P( E, A, B, C, D, R(21) );
|
||||
P( D, E, A, B, C, R(22) );
|
||||
P( C, D, E, A, B, R(23) );
|
||||
P( B, C, D, E, A, R(24) );
|
||||
P( A, B, C, D, E, R(25) );
|
||||
P( E, A, B, C, D, R(26) );
|
||||
P( D, E, A, B, C, R(27) );
|
||||
P( C, D, E, A, B, R(28) );
|
||||
P( B, C, D, E, A, R(29) );
|
||||
P( A, B, C, D, E, R(30) );
|
||||
P( E, A, B, C, D, R(31) );
|
||||
P( D, E, A, B, C, R(32) );
|
||||
P( C, D, E, A, B, R(33) );
|
||||
P( B, C, D, E, A, R(34) );
|
||||
P( A, B, C, D, E, R(35) );
|
||||
P( E, A, B, C, D, R(36) );
|
||||
P( D, E, A, B, C, R(37) );
|
||||
P( C, D, E, A, B, R(38) );
|
||||
P( B, C, D, E, A, R(39) );
|
||||
|
||||
#undef K
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) ((x & y) | (z & (x | y)))
|
||||
#define K 0x8F1BBCDC
|
||||
|
||||
P( A, B, C, D, E, R(40) );
|
||||
P( E, A, B, C, D, R(41) );
|
||||
P( D, E, A, B, C, R(42) );
|
||||
P( C, D, E, A, B, R(43) );
|
||||
P( B, C, D, E, A, R(44) );
|
||||
P( A, B, C, D, E, R(45) );
|
||||
P( E, A, B, C, D, R(46) );
|
||||
P( D, E, A, B, C, R(47) );
|
||||
P( C, D, E, A, B, R(48) );
|
||||
P( B, C, D, E, A, R(49) );
|
||||
P( A, B, C, D, E, R(50) );
|
||||
P( E, A, B, C, D, R(51) );
|
||||
P( D, E, A, B, C, R(52) );
|
||||
P( C, D, E, A, B, R(53) );
|
||||
P( B, C, D, E, A, R(54) );
|
||||
P( A, B, C, D, E, R(55) );
|
||||
P( E, A, B, C, D, R(56) );
|
||||
P( D, E, A, B, C, R(57) );
|
||||
P( C, D, E, A, B, R(58) );
|
||||
P( B, C, D, E, A, R(59) );
|
||||
|
||||
#undef K
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
#define K 0xCA62C1D6
|
||||
|
||||
P( A, B, C, D, E, R(60) );
|
||||
P( E, A, B, C, D, R(61) );
|
||||
P( D, E, A, B, C, R(62) );
|
||||
P( C, D, E, A, B, R(63) );
|
||||
P( B, C, D, E, A, R(64) );
|
||||
P( A, B, C, D, E, R(65) );
|
||||
P( E, A, B, C, D, R(66) );
|
||||
P( D, E, A, B, C, R(67) );
|
||||
P( C, D, E, A, B, R(68) );
|
||||
P( B, C, D, E, A, R(69) );
|
||||
P( A, B, C, D, E, R(70) );
|
||||
P( E, A, B, C, D, R(71) );
|
||||
P( D, E, A, B, C, R(72) );
|
||||
P( C, D, E, A, B, R(73) );
|
||||
P( B, C, D, E, A, R(74) );
|
||||
P( A, B, C, D, E, R(75) );
|
||||
P( E, A, B, C, D, R(76) );
|
||||
P( D, E, A, B, C, R(77) );
|
||||
P( C, D, E, A, B, R(78) );
|
||||
P( B, C, D, E, A, R(79) );
|
||||
|
||||
#undef K
|
||||
#undef F
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
ctx->state[4] += E;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 process buffer
|
||||
*/
|
||||
void sha1_update( sha1_context *ctx, unsigned char *input, int ilen )
|
||||
{
|
||||
int fill;
|
||||
unsigned long left;
|
||||
|
||||
if( ilen <= 0 )
|
||||
return;
|
||||
|
||||
left = ctx->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->total[0] += ilen;
|
||||
ctx->total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if( ctx->total[0] < (unsigned long) ilen )
|
||||
ctx->total[1]++;
|
||||
|
||||
if( left && ilen >= fill )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, fill );
|
||||
sha1_process( ctx, ctx->buffer );
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while( ilen >= 64 )
|
||||
{
|
||||
sha1_process( ctx, input );
|
||||
input += 64;
|
||||
ilen -= 64;
|
||||
}
|
||||
|
||||
if( ilen > 0 )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, ilen );
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char sha1_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* SHA-1 final digest
|
||||
*/
|
||||
void sha1_finish( sha1_context *ctx, unsigned char output[20] )
|
||||
{
|
||||
unsigned long last, padn;
|
||||
unsigned long high, low;
|
||||
unsigned char msglen[8];
|
||||
|
||||
high = ( ctx->total[0] >> 29 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_ULONG_BE( high, msglen, 0 );
|
||||
PUT_ULONG_BE( low, msglen, 4 );
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
sha1_update( ctx, (unsigned char *) sha1_padding, padn );
|
||||
sha1_update( ctx, msglen, 8 );
|
||||
|
||||
PUT_ULONG_BE( ctx->state[0], output, 0 );
|
||||
PUT_ULONG_BE( ctx->state[1], output, 4 );
|
||||
PUT_ULONG_BE( ctx->state[2], output, 8 );
|
||||
PUT_ULONG_BE( ctx->state[3], output, 12 );
|
||||
PUT_ULONG_BE( ctx->state[4], output, 16 );
|
||||
}
|
||||
|
||||
/*
|
||||
* output = SHA-1( input buffer )
|
||||
*/
|
||||
void sha1( unsigned char *input, int ilen, unsigned char output[20] )
|
||||
{
|
||||
sha1_context ctx;
|
||||
|
||||
sha1_starts( &ctx );
|
||||
sha1_update( &ctx, input, ilen );
|
||||
sha1_finish( &ctx, output );
|
||||
|
||||
memset( &ctx, 0, sizeof( sha1_context ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* output = SHA-1( file contents )
|
||||
*/
|
||||
int sha1_file( char *path, unsigned char output[20] )
|
||||
{
|
||||
FILE *f;
|
||||
size_t n;
|
||||
sha1_context ctx;
|
||||
unsigned char buf[1024];
|
||||
|
||||
if( ( f = fopen( path, "rb" ) ) == NULL )
|
||||
return( 1 );
|
||||
|
||||
sha1_starts( &ctx );
|
||||
|
||||
while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
|
||||
sha1_update( &ctx, buf, (int) n );
|
||||
|
||||
sha1_finish( &ctx, output );
|
||||
|
||||
memset( &ctx, 0, sizeof( sha1_context ) );
|
||||
|
||||
if( ferror( f ) != 0 )
|
||||
{
|
||||
fclose( f );
|
||||
return( 2 );
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 HMAC context setup
|
||||
*/
|
||||
void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen )
|
||||
{
|
||||
int i;
|
||||
unsigned char sum[20];
|
||||
|
||||
if( keylen > 64 )
|
||||
{
|
||||
sha1( key, keylen, sum );
|
||||
keylen = 20;
|
||||
key = sum;
|
||||
}
|
||||
|
||||
memset( ctx->ipad, 0x36, 64 );
|
||||
memset( ctx->opad, 0x5C, 64 );
|
||||
|
||||
for( i = 0; i < keylen; i++ )
|
||||
{
|
||||
ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
|
||||
ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
|
||||
}
|
||||
|
||||
sha1_starts( ctx );
|
||||
sha1_update( ctx, ctx->ipad, 64 );
|
||||
|
||||
memset( sum, 0, sizeof( sum ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 HMAC process buffer
|
||||
*/
|
||||
void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen )
|
||||
{
|
||||
sha1_update( ctx, input, ilen );
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 HMAC final digest
|
||||
*/
|
||||
void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )
|
||||
{
|
||||
unsigned char tmpbuf[20];
|
||||
|
||||
sha1_finish( ctx, tmpbuf );
|
||||
sha1_starts( ctx );
|
||||
sha1_update( ctx, ctx->opad, 64 );
|
||||
sha1_update( ctx, tmpbuf, 20 );
|
||||
sha1_finish( ctx, output );
|
||||
|
||||
memset( tmpbuf, 0, sizeof( tmpbuf ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* output = HMAC-SHA-1( hmac key, input buffer )
|
||||
*/
|
||||
void sha1_hmac( unsigned char *key, int keylen,
|
||||
unsigned char *input, int ilen,
|
||||
unsigned char output[20] )
|
||||
{
|
||||
sha1_context ctx;
|
||||
|
||||
sha1_hmac_starts( &ctx, key, keylen );
|
||||
sha1_hmac_update( &ctx, input, ilen );
|
||||
sha1_hmac_finish( &ctx, output );
|
||||
|
||||
memset( &ctx, 0, sizeof( sha1_context ) );
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_SELF_TEST)
|
||||
/*
|
||||
* FIPS-180-1 test vectors
|
||||
*/
|
||||
static unsigned char sha1_test_buf[3][57] =
|
||||
{
|
||||
{ "abc" },
|
||||
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
|
||||
{ "" }
|
||||
};
|
||||
|
||||
static const int sha1_test_buflen[3] =
|
||||
{
|
||||
3, 56, 1000
|
||||
};
|
||||
|
||||
static const unsigned char sha1_test_sum[3][20] =
|
||||
{
|
||||
{ 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
|
||||
0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
|
||||
{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
|
||||
0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
|
||||
{ 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
|
||||
0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
|
||||
};
|
||||
|
||||
/*
|
||||
* RFC 2202 test vectors
|
||||
*/
|
||||
static unsigned char sha1_hmac_test_key[7][26] =
|
||||
{
|
||||
{ "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
|
||||
"\x0B\x0B\x0B\x0B" },
|
||||
{ "Jefe" },
|
||||
{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA" },
|
||||
{ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
|
||||
"\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
|
||||
{ "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
|
||||
"\x0C\x0C\x0C\x0C" },
|
||||
{ "" }, /* 0xAA 80 times */
|
||||
{ "" }
|
||||
};
|
||||
|
||||
static const int sha1_hmac_test_keylen[7] =
|
||||
{
|
||||
20, 4, 20, 25, 20, 80, 80
|
||||
};
|
||||
|
||||
static unsigned char sha1_hmac_test_buf[7][74] =
|
||||
{
|
||||
{ "Hi There" },
|
||||
{ "what do ya want for nothing?" },
|
||||
{ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
|
||||
{ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
|
||||
{ "Test With Truncation" },
|
||||
{ "Test Using Larger Than Block-Size Key - Hash Key First" },
|
||||
{ "Test Using Larger Than Block-Size Key and Larger"
|
||||
" Than One Block-Size Data" }
|
||||
};
|
||||
|
||||
static const int sha1_hmac_test_buflen[7] =
|
||||
{
|
||||
8, 28, 50, 50, 20, 54, 73
|
||||
};
|
||||
|
||||
static const unsigned char sha1_hmac_test_sum[7][20] =
|
||||
{
|
||||
{ 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B,
|
||||
0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 },
|
||||
{ 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74,
|
||||
0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 },
|
||||
{ 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3,
|
||||
0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 },
|
||||
{ 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84,
|
||||
0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA },
|
||||
{ 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2,
|
||||
0x7B, 0xE1 },
|
||||
{ 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70,
|
||||
0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 },
|
||||
{ 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B,
|
||||
0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Checkup routine
|
||||
*/
|
||||
int sha1_self_test( int verbose )
|
||||
{
|
||||
int i, j, buflen;
|
||||
unsigned char buf[1024];
|
||||
unsigned char sha1sum[20];
|
||||
sha1_context ctx;
|
||||
|
||||
/*
|
||||
* SHA-1
|
||||
*/
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
if( verbose != 0 )
|
||||
printf( " SHA-1 test #%d: ", i + 1 );
|
||||
|
||||
sha1_starts( &ctx );
|
||||
|
||||
if( i == 2 )
|
||||
{
|
||||
memset( buf, 'a', buflen = 1000 );
|
||||
|
||||
for( j = 0; j < 1000; j++ )
|
||||
sha1_update( &ctx, buf, buflen );
|
||||
}
|
||||
else
|
||||
sha1_update( &ctx, sha1_test_buf[i],
|
||||
sha1_test_buflen[i] );
|
||||
|
||||
sha1_finish( &ctx, sha1sum );
|
||||
|
||||
if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
|
||||
{
|
||||
if( verbose != 0 )
|
||||
printf( "failed\n" );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
if( verbose != 0 )
|
||||
printf( "passed\n" );
|
||||
}
|
||||
|
||||
if( verbose != 0 )
|
||||
printf( "\n" );
|
||||
|
||||
for( i = 0; i < 7; i++ )
|
||||
{
|
||||
if( verbose != 0 )
|
||||
printf( " HMAC-SHA-1 test #%d: ", i + 1 );
|
||||
|
||||
if( i == 5 || i == 6 )
|
||||
{
|
||||
memset( buf, '\xAA', buflen = 80 );
|
||||
sha1_hmac_starts( &ctx, buf, buflen );
|
||||
}
|
||||
else
|
||||
sha1_hmac_starts( &ctx, sha1_hmac_test_key[i],
|
||||
sha1_hmac_test_keylen[i] );
|
||||
|
||||
sha1_hmac_update( &ctx, sha1_hmac_test_buf[i],
|
||||
sha1_hmac_test_buflen[i] );
|
||||
|
||||
sha1_hmac_finish( &ctx, sha1sum );
|
||||
|
||||
buflen = ( i == 4 ) ? 12 : 20;
|
||||
|
||||
if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
|
||||
{
|
||||
if( verbose != 0 )
|
||||
printf( "failed\n" );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
if( verbose != 0 )
|
||||
printf( "passed\n" );
|
||||
}
|
||||
|
||||
if( verbose != 0 )
|
||||
printf( "\n" );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//#endif
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* \file sha1.h
|
||||
*
|
||||
* Copyright (C) 2006-2009, Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Joined copyright on original XySSL code with: Christophe Devine
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#ifndef POLARSSL_SHA1_H
|
||||
#define POLARSSL_SHA1_H
|
||||
|
||||
/**
|
||||
* \brief SHA-1 context structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned long total[2]; /*!< number of bytes processed */
|
||||
unsigned long state[5]; /*!< intermediate digest state */
|
||||
unsigned char buffer[64]; /*!< data block being processed */
|
||||
|
||||
unsigned char ipad[64]; /*!< HMAC: inner padding */
|
||||
unsigned char opad[64]; /*!< HMAC: outer padding */
|
||||
}
|
||||
sha1_context;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief SHA-1 context setup
|
||||
*
|
||||
* \param ctx context to be initialized
|
||||
*/
|
||||
void sha1_starts( sha1_context *ctx );
|
||||
|
||||
/**
|
||||
* \brief SHA-1 process buffer
|
||||
*
|
||||
* \param ctx SHA-1 context
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
*/
|
||||
void sha1_update( sha1_context *ctx, unsigned char *input, int ilen );
|
||||
|
||||
/**
|
||||
* \brief SHA-1 final digest
|
||||
*
|
||||
* \param ctx SHA-1 context
|
||||
* \param output SHA-1 checksum result
|
||||
*/
|
||||
void sha1_finish( sha1_context *ctx, unsigned char output[20] );
|
||||
|
||||
/**
|
||||
* \brief Output = SHA-1( input buffer )
|
||||
*
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* \param output SHA-1 checksum result
|
||||
*/
|
||||
void sha1( unsigned char *input, int ilen, unsigned char output[20] );
|
||||
|
||||
/**
|
||||
* \brief Output = SHA-1( file contents )
|
||||
*
|
||||
* \param path input file name
|
||||
* \param output SHA-1 checksum result
|
||||
*
|
||||
* \return 0 if successful, 1 if fopen failed,
|
||||
* or 2 if fread failed
|
||||
*/
|
||||
int sha1_file( char *path, unsigned char output[20] );
|
||||
|
||||
/**
|
||||
* \brief SHA-1 HMAC context setup
|
||||
*
|
||||
* \param ctx HMAC context to be initialized
|
||||
* \param key HMAC secret key
|
||||
* \param keylen length of the HMAC key
|
||||
*/
|
||||
void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen );
|
||||
|
||||
/**
|
||||
* \brief SHA-1 HMAC process buffer
|
||||
*
|
||||
* \param ctx HMAC context
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
*/
|
||||
void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen );
|
||||
|
||||
/**
|
||||
* \brief SHA-1 HMAC final digest
|
||||
*
|
||||
* \param ctx HMAC context
|
||||
* \param output SHA-1 HMAC checksum result
|
||||
*/
|
||||
void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] );
|
||||
|
||||
/**
|
||||
* \brief Output = HMAC-SHA-1( hmac key, input buffer )
|
||||
*
|
||||
* \param key HMAC secret key
|
||||
* \param keylen length of the HMAC key
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* \param output HMAC-SHA-1 result
|
||||
*/
|
||||
void sha1_hmac( unsigned char *key, int keylen,
|
||||
unsigned char *input, int ilen,
|
||||
unsigned char output[20] );
|
||||
|
||||
/**
|
||||
* \brief Checkup routine
|
||||
*
|
||||
* \return 0 if successful, or 1 if the test failed
|
||||
*/
|
||||
int sha1_self_test( int verbose );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* sha1.h */
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
// Licensed under the terms of the GNU GPL, version 2
|
||||
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||||
|
||||
#ifndef _TOOLS_H
|
||||
#define _TOOLS_H
|
||||
#include "sha1.h"
|
||||
|
||||
// bignum
|
||||
int bn_compare(u8 *a, u8 *b, u32 n);
|
||||
void bn_sub_modulus(u8 *a, u8 *N, u32 n);
|
||||
void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n);
|
||||
void bn_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n);
|
||||
void bn_inv(u8 *d, u8 *a, u8 *N, u32 n); // only for prime N
|
||||
void bn_exp(u8 *d, u8 *a, u8 *N, u32 n, u8 *e, u32 en);
|
||||
|
||||
void generate_ecdsa(u8 *R, u8 *S, u8 *k, u8 *hash);
|
||||
|
||||
void ec_priv_to_pub(u8 *k, u8 *Q);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef _DEBUGINTERFACE_H
|
||||
#define _DEBUGINTERFACE_H
|
||||
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
class DebugInterface
|
||||
{
|
||||
protected:
|
||||
virtual ~DebugInterface() {}
|
||||
|
||||
public:
|
||||
virtual void disasm(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
|
||||
virtual void getRawMemoryString(int /*memory*/, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
|
||||
virtual int getInstructionSize(int /*instruction*/) {return 1;}
|
||||
virtual bool isAlive() {return true;}
|
||||
virtual bool isBreakpoint(unsigned int /*address*/) {return false;}
|
||||
virtual void setBreakpoint(unsigned int /*address*/){}
|
||||
virtual void clearBreakpoint(unsigned int /*address*/){}
|
||||
virtual void clearAllBreakpoints() {}
|
||||
virtual void toggleBreakpoint(unsigned int /*address*/){}
|
||||
virtual bool isMemCheck(unsigned int /*address*/) {return false;}
|
||||
virtual void toggleMemCheck(unsigned int /*address*/){}
|
||||
virtual unsigned int readMemory(unsigned int /*address*/){return 0;}
|
||||
virtual void writeExtraMemory(int /*memory*/, unsigned int /*value*/, unsigned int /*address*/) {}
|
||||
virtual unsigned int readExtraMemory(int /*memory*/, unsigned int /*address*/){return 0;}
|
||||
virtual unsigned int readInstruction(unsigned int /*address*/){return 0;}
|
||||
virtual unsigned int getPC() {return 0;}
|
||||
virtual void setPC(unsigned int /*address*/) {}
|
||||
virtual void step() {}
|
||||
virtual void runToBreakpoint() {}
|
||||
virtual void breakNow() {}
|
||||
virtual void insertBLR(unsigned int /*address*/, unsigned int) {}
|
||||
virtual void showJitResults(unsigned int /*address*/) {};
|
||||
virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;}
|
||||
virtual std::string getDescription(unsigned int /*address*/) = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,446 @@
|
|||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
|
||||
// For companies(Austin,TX): If you would like to get my resume, send an email.
|
||||
//
|
||||
// The source is free, but if you want to use it, mention my name and e-mail address
|
||||
//
|
||||
// History:
|
||||
// 1.0 Initial version Zoltan Csizmadia
|
||||
// 1.1 WhineCube version Masken
|
||||
// 1.2 Dolphin version Masken
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include "ExtendedTrace.h"
|
||||
using namespace std;
|
||||
|
||||
#include <tchar.h>
|
||||
#include <ImageHlp.h>
|
||||
|
||||
#define BUFFERSIZE 0x200
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
// Unicode safe char* -> TCHAR* conversion
|
||||
void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
|
||||
{
|
||||
#if defined(UNICODE)||defined(_UNICODE)
|
||||
ULONG index = 0;
|
||||
PCSTR lpAct = lpszIn;
|
||||
|
||||
for( ; ; lpAct++ )
|
||||
{
|
||||
lpszOut[index++] = (TCHAR)(*lpAct);
|
||||
if ( *lpAct == 0 )
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// This is trivial :)
|
||||
strcpy( lpszOut, lpszIn );
|
||||
#endif
|
||||
}
|
||||
|
||||
// Let's figure out the path for the symbol files
|
||||
// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;" + lpszIniPath
|
||||
// Note: There is no size check for lpszSymbolPath!
|
||||
static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath )
|
||||
{
|
||||
CHAR lpszPath[BUFFERSIZE];
|
||||
|
||||
// Creating the default path
|
||||
// ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%\System32;"
|
||||
strcpy( lpszSymbolPath, "." );
|
||||
|
||||
// environment variable _NT_SYMBOL_PATH
|
||||
if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
|
||||
{
|
||||
strcat( lpszSymbolPath, ";" );
|
||||
strcat( lpszSymbolPath, lpszPath );
|
||||
}
|
||||
|
||||
// environment variable _NT_ALTERNATE_SYMBOL_PATH
|
||||
if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
|
||||
{
|
||||
strcat( lpszSymbolPath, ";" );
|
||||
strcat( lpszSymbolPath, lpszPath );
|
||||
}
|
||||
|
||||
// environment variable SYSTEMROOT
|
||||
if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) )
|
||||
{
|
||||
strcat( lpszSymbolPath, ";" );
|
||||
strcat( lpszSymbolPath, lpszPath );
|
||||
strcat( lpszSymbolPath, ";" );
|
||||
|
||||
// SYSTEMROOT\System32
|
||||
strcat( lpszSymbolPath, lpszPath );
|
||||
strcat( lpszSymbolPath, "\\System32" );
|
||||
}
|
||||
|
||||
// Add user defined path
|
||||
if ( lpszIniPath != NULL )
|
||||
if ( lpszIniPath[0] != '\0' )
|
||||
{
|
||||
strcat( lpszSymbolPath, ";" );
|
||||
strcat( lpszSymbolPath, lpszIniPath );
|
||||
}
|
||||
}
|
||||
|
||||
// Uninitialize the loaded symbol files
|
||||
BOOL UninitSymInfo() {
|
||||
return SymCleanup( GetCurrentProcess() );
|
||||
}
|
||||
|
||||
// Initializes the symbol files
|
||||
BOOL InitSymInfo( PCSTR lpszInitialSymbolPath )
|
||||
{
|
||||
CHAR lpszSymbolPath[BUFFERSIZE];
|
||||
DWORD symOptions = SymGetOptions();
|
||||
|
||||
symOptions |= SYMOPT_LOAD_LINES;
|
||||
symOptions &= ~SYMOPT_UNDNAME;
|
||||
SymSetOptions( symOptions );
|
||||
InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath );
|
||||
|
||||
return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE);
|
||||
}
|
||||
|
||||
// Get the module name from a given address
|
||||
static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule )
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
IMAGEHLP_MODULE moduleInfo;
|
||||
|
||||
::ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
|
||||
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
|
||||
|
||||
if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) )
|
||||
{
|
||||
// Got it!
|
||||
PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule );
|
||||
ret = TRUE;
|
||||
}
|
||||
else
|
||||
// Not found :(
|
||||
_tcscpy( lpszModule, _T("?") );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get function prototype and parameter info from ip address and stack address
|
||||
static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol )
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
DWORD dwDisp = 0;
|
||||
DWORD dwSymSize = 10000;
|
||||
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
|
||||
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
|
||||
LPTSTR lpszParamSep = NULL;
|
||||
LPTSTR lpszParsed = lpszUnDSymbol;
|
||||
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
|
||||
|
||||
::ZeroMemory( pSym, dwSymSize );
|
||||
pSym->SizeOfStruct = dwSymSize;
|
||||
pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL);
|
||||
|
||||
// Set the default to unknown
|
||||
_tcscpy( lpszSymbol, _T("?") );
|
||||
|
||||
// Get symbol info for IP
|
||||
#ifndef _M_X64
|
||||
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
|
||||
#else
|
||||
//makes it compile but hell im not sure if this works...
|
||||
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) )
|
||||
#endif
|
||||
{
|
||||
// Make the symbol readable for humans
|
||||
UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
|
||||
UNDNAME_COMPLETE |
|
||||
UNDNAME_NO_THISTYPE |
|
||||
UNDNAME_NO_SPECIAL_SYMS |
|
||||
UNDNAME_NO_MEMBER_TYPE |
|
||||
UNDNAME_NO_MS_KEYWORDS |
|
||||
UNDNAME_NO_ACCESS_SPECIFIERS );
|
||||
|
||||
// Symbol information is ANSI string
|
||||
PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol );
|
||||
|
||||
// I am just smarter than the symbol file :)
|
||||
if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 )
|
||||
_tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)"));
|
||||
else
|
||||
if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 )
|
||||
_tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)"));
|
||||
else
|
||||
if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 )
|
||||
_tcscpy(lpszUnDSymbol, _T("mainCRTStartup()"));
|
||||
else
|
||||
if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 )
|
||||
_tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)"));
|
||||
else
|
||||
if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 )
|
||||
_tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()"));
|
||||
|
||||
lpszSymbol[0] = _T('\0');
|
||||
|
||||
// Let's go through the stack, and modify the function prototype, and insert the actual
|
||||
// parameter values from the stack
|
||||
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
|
||||
{
|
||||
ULONG index = 0;
|
||||
for( ; ; index++ )
|
||||
{
|
||||
lpszParamSep = _tcschr( lpszParsed, _T(',') );
|
||||
if ( lpszParamSep == NULL )
|
||||
break;
|
||||
|
||||
*lpszParamSep = _T('\0');
|
||||
|
||||
_tcscat( lpszSymbol, lpszParsed );
|
||||
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) );
|
||||
|
||||
lpszParsed = lpszParamSep + 1;
|
||||
}
|
||||
|
||||
lpszParamSep = _tcschr( lpszParsed, _T(')') );
|
||||
if ( lpszParamSep != NULL )
|
||||
{
|
||||
*lpszParamSep = _T('\0');
|
||||
|
||||
_tcscat( lpszSymbol, lpszParsed );
|
||||
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) );
|
||||
|
||||
lpszParsed = lpszParamSep + 1;
|
||||
}
|
||||
}
|
||||
|
||||
_tcscat( lpszSymbol, lpszParsed );
|
||||
|
||||
ret = TRUE;
|
||||
}
|
||||
GlobalFree( pSym );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get source file name and line number from IP address
|
||||
// The output format is: "sourcefile(linenumber)" or
|
||||
// "modulename!address" or
|
||||
// "address"
|
||||
static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
IMAGEHLP_LINE lineInfo;
|
||||
DWORD dwDisp;
|
||||
TCHAR lpszFileName[BUFFERSIZE] = _T("");
|
||||
TCHAR lpModuleInfo[BUFFERSIZE] = _T("");
|
||||
|
||||
_tcscpy( lpszSourceInfo, _T("?(?)") );
|
||||
|
||||
::ZeroMemory( &lineInfo, sizeof( lineInfo ) );
|
||||
lineInfo.SizeOfStruct = sizeof( lineInfo );
|
||||
|
||||
if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) )
|
||||
{
|
||||
// Got it. Let's use "sourcefile(linenumber)" format
|
||||
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
|
||||
TCHAR fname[_MAX_FNAME];
|
||||
TCHAR ext[_MAX_EXT];
|
||||
_tsplitpath(lpszFileName, NULL, NULL, fname, ext);
|
||||
_stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
|
||||
ret = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is no source file information. :(
|
||||
// Let's use the "modulename!address" format
|
||||
GetModuleNameFromAddress( address, lpModuleInfo );
|
||||
|
||||
if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0'))
|
||||
// There is no modulename information. :((
|
||||
// Let's use the "address" format
|
||||
_stprintf( lpszSourceInfo, _T("0x%08X"), address );
|
||||
else
|
||||
_stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address );
|
||||
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
|
||||
{
|
||||
STACKFRAME callStack;
|
||||
BOOL bResult;
|
||||
CONTEXT context;
|
||||
TCHAR symInfo[BUFFERSIZE] = _T("?");
|
||||
TCHAR srcInfo[BUFFERSIZE] = _T("?");
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
|
||||
// If it's not this thread, let's suspend it, and resume it at the end
|
||||
if ( hThread != GetCurrentThread() )
|
||||
if ( SuspendThread( hThread ) == -1 )
|
||||
{
|
||||
// whaaat ?!
|
||||
etfprint(file, "Call stack info failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
::ZeroMemory( &context, sizeof(context) );
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
|
||||
if ( !GetThreadContext( hThread, &context ) )
|
||||
{
|
||||
etfprint(file, "Call stack info failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
::ZeroMemory( &callStack, sizeof(callStack) );
|
||||
#ifndef _M_X64
|
||||
callStack.AddrPC.Offset = context.Eip;
|
||||
callStack.AddrStack.Offset = context.Esp;
|
||||
callStack.AddrFrame.Offset = context.Ebp;
|
||||
#else
|
||||
callStack.AddrPC.Offset = context.Rip;
|
||||
callStack.AddrStack.Offset = context.Rsp;
|
||||
callStack.AddrFrame.Offset = context.Rbp;
|
||||
#endif
|
||||
callStack.AddrPC.Mode = AddrModeFlat;
|
||||
callStack.AddrStack.Mode = AddrModeFlat;
|
||||
callStack.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
etfprint(file, "Call stack info: \n");
|
||||
etfprint(file, lpszMessage);
|
||||
|
||||
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
|
||||
GetSourceInfoFromAddress( (ULONG)callStack.AddrPC.Offset, srcInfo );
|
||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||
|
||||
for( ULONG index = 0; ; index++ )
|
||||
{
|
||||
bResult = StackWalk(
|
||||
IMAGE_FILE_MACHINE_I386,
|
||||
hProcess,
|
||||
hThread,
|
||||
&callStack,
|
||||
NULL,
|
||||
NULL,
|
||||
SymFunctionTableAccess,
|
||||
SymGetModuleBase,
|
||||
NULL);
|
||||
|
||||
if ( index == 0 )
|
||||
continue;
|
||||
|
||||
if( !bResult || callStack.AddrFrame.Offset == 0 )
|
||||
break;
|
||||
|
||||
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
|
||||
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
|
||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||
|
||||
}
|
||||
|
||||
if ( hThread != GetCurrentThread() )
|
||||
ResumeThread( hThread );
|
||||
}
|
||||
|
||||
#ifndef UNICODE
|
||||
|
||||
void StackTrace( HANDLE hThread, wchar_t const*lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
|
||||
{
|
||||
// TODO: remove when Common builds as unicode
|
||||
size_t origsize = wcslen(lpszMessage) + 1;
|
||||
const size_t newsize = 100;
|
||||
size_t convertedChars = 0;
|
||||
char nstring[newsize];
|
||||
wcstombs_s(&convertedChars, nstring, origsize, lpszMessage, _TRUNCATE);
|
||||
|
||||
StackTrace(hThread, nstring, file, eip, esp, ebp );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
|
||||
{
|
||||
STACKFRAME callStack;
|
||||
BOOL bResult;
|
||||
TCHAR symInfo[BUFFERSIZE] = _T("?");
|
||||
TCHAR srcInfo[BUFFERSIZE] = _T("?");
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
|
||||
// If it's not this thread, let's suspend it, and resume it at the end
|
||||
if ( hThread != GetCurrentThread() )
|
||||
if ( SuspendThread( hThread ) == -1 )
|
||||
{
|
||||
// whaaat ?!
|
||||
etfprint(file, "Call stack info failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
::ZeroMemory( &callStack, sizeof(callStack) );
|
||||
callStack.AddrPC.Offset = eip;
|
||||
callStack.AddrStack.Offset = esp;
|
||||
callStack.AddrFrame.Offset = ebp;
|
||||
callStack.AddrPC.Mode = AddrModeFlat;
|
||||
callStack.AddrStack.Mode = AddrModeFlat;
|
||||
callStack.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
etfprint(file, "Call stack info: \n");
|
||||
etfprint(file, lpszMessage);
|
||||
|
||||
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
|
||||
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
|
||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||
|
||||
for( ULONG index = 0; ; index++ )
|
||||
{
|
||||
bResult = StackWalk(
|
||||
IMAGE_FILE_MACHINE_I386,
|
||||
hProcess,
|
||||
hThread,
|
||||
&callStack,
|
||||
NULL,
|
||||
NULL,
|
||||
SymFunctionTableAccess,
|
||||
SymGetModuleBase,
|
||||
NULL);
|
||||
|
||||
if ( index == 0 )
|
||||
continue;
|
||||
|
||||
if( !bResult || callStack.AddrFrame.Offset == 0 )
|
||||
break;
|
||||
|
||||
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
|
||||
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
|
||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||
|
||||
}
|
||||
|
||||
if ( hThread != GetCurrentThread() )
|
||||
ResumeThread( hThread );
|
||||
}
|
||||
|
||||
char g_uefbuf[2048];
|
||||
|
||||
void etfprintf(FILE *file, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int len = vsprintf(g_uefbuf, format, ap);
|
||||
fwrite(g_uefbuf, 1, len, file);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void etfprint(FILE *file, const std::string &text) {
|
||||
size_t len = text.length();
|
||||
fwrite(text.data(), 1, len, file);
|
||||
}
|
||||
|
||||
#endif //WIN32
|
|
@ -0,0 +1,54 @@
|
|||
// -----------------------------------------------------------------------------------------
|
||||
//
|
||||
// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
|
||||
// For companies(Austin,TX): If you would like to get my resume, send an email.
|
||||
//
|
||||
// The source is free, but if you want to use it, mention my name and e-mail address
|
||||
//
|
||||
// History:
|
||||
// 1.0 Initial version Zoltan Csizmadia
|
||||
// 1.1 WhineCube version Masken
|
||||
// 1.2 Dolphin version Masken
|
||||
//
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _EXTENDEDTRACE_H_INCLUDED_
|
||||
#define _EXTENDEDTRACE_H_INCLUDED_
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#pragma comment( lib, "imagehlp.lib" )
|
||||
|
||||
#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) InitSymInfo( IniSymbolPath )
|
||||
#define EXTENDEDTRACEUNINITIALIZE() UninitSymInfo()
|
||||
#define STACKTRACE(file) StackTrace( GetCurrentThread(), _T(""), file)
|
||||
#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), _T(""), file, eip, esp, ebp)
|
||||
// class File;
|
||||
|
||||
BOOL InitSymInfo( PCSTR );
|
||||
BOOL UninitSymInfo();
|
||||
void StackTrace( HANDLE, LPCTSTR, FILE *file);
|
||||
void StackTrace( HANDLE, LPCTSTR, FILE *file, DWORD eip, DWORD esp, DWORD ebp);
|
||||
void StackTrace( HANDLE hThread, wchar_t const* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp);
|
||||
|
||||
// functions by Masken
|
||||
void etfprintf(FILE *file, const char *format, ...);
|
||||
void etfprint(FILE *file, const std::string &text);
|
||||
#define UEFBUFSIZE 2048
|
||||
extern char g_uefbuf[UEFBUFSIZE];
|
||||
|
||||
#else // not WIN32
|
||||
|
||||
#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) ((void)0)
|
||||
#define EXTENDEDTRACEUNINITIALIZE() ((void)0)
|
||||
#define STACKTRACE(file) ((void)0)
|
||||
#define STACKTRACE2(file, eip, esp, ebp) ((void)0)
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#endif // _EXTENDEDTRACE_H_INCLUDED_
|
|
@ -0,0 +1,51 @@
|
|||
// 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/
|
||||
#ifndef FPU_ROUND_MODE_H_
|
||||
#define FPU_ROUND_MODE_H_
|
||||
#include "Common.h"
|
||||
|
||||
namespace FPURoundMode
|
||||
{
|
||||
enum RoundModes
|
||||
{
|
||||
ROUND_NEAR = 0,
|
||||
ROUND_CHOP,
|
||||
ROUND_UP,
|
||||
ROUND_DOWN
|
||||
};
|
||||
enum PrecisionModes {
|
||||
PREC_24 = 0,
|
||||
PREC_53,
|
||||
PREC_64
|
||||
};
|
||||
void SetRoundMode(u32 mode);
|
||||
|
||||
void SetPrecisionMode(u32 mode);
|
||||
|
||||
void SetSIMDMode(u32 mode);
|
||||
|
||||
/*
|
||||
There are two different flavors of float to int conversion:
|
||||
_mm_cvtps_epi32() and _mm_cvttps_epi32(). The first rounds
|
||||
according to the MXCSR rounding bits. The second one always
|
||||
uses round towards zero.
|
||||
*/
|
||||
void SaveSIMDState();
|
||||
void LoadSIMDState();
|
||||
void LoadDefaultSIMDState();
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
// 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 "FPURoundMode.h"
|
||||
|
||||
// Generic, do nothing
|
||||
namespace FPURoundMode
|
||||
{
|
||||
void SetRoundMode(u32 mode)
|
||||
{
|
||||
}
|
||||
void SetPrecisionMode(u32 mode)
|
||||
{
|
||||
}
|
||||
void SetSIMDMode(u32 mode)
|
||||
{
|
||||
}
|
||||
void SaveSIMDState()
|
||||
{
|
||||
}
|
||||
void LoadSIMDState()
|
||||
{
|
||||
}
|
||||
void LoadDefaultSIMDState()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
// 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 "FPURoundMode.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
static const unsigned short FPU_ROUND_NEAR = 0 << 10;
|
||||
static const unsigned short FPU_ROUND_DOWN = 1 << 10;
|
||||
static const unsigned short FPU_ROUND_UP = 2 << 10;
|
||||
static const unsigned short FPU_ROUND_CHOP = 3 << 10;
|
||||
static const unsigned short FPU_ROUND_MASK = 3 << 10;
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
const u32 MASKS = 0x1F80; // mask away the interrupts.
|
||||
const u32 DAZ = 0x40;
|
||||
const u32 FTZ = 0x8000;
|
||||
|
||||
namespace FPURoundMode
|
||||
{
|
||||
// Get the default SSE states here.
|
||||
static u32 saved_sse_state = _mm_getcsr();
|
||||
static const u32 default_sse_state = _mm_getcsr();
|
||||
|
||||
void SetRoundMode(u32 mode)
|
||||
{
|
||||
// Set FPU rounding mode to mimic the PowerPC's
|
||||
#ifdef _M_IX86
|
||||
// This shouldn't really be needed anymore since we use SSE
|
||||
#ifdef _WIN32
|
||||
const int table[4] =
|
||||
{
|
||||
_RC_NEAR,
|
||||
_RC_CHOP,
|
||||
_RC_UP,
|
||||
_RC_DOWN
|
||||
};
|
||||
_set_controlfp(_MCW_RC, table[mode]);
|
||||
#else
|
||||
const unsigned short table[4] =
|
||||
{
|
||||
FPU_ROUND_NEAR,
|
||||
FPU_ROUND_CHOP,
|
||||
FPU_ROUND_UP,
|
||||
FPU_ROUND_DOWN
|
||||
};
|
||||
unsigned short mode;
|
||||
asm ("fstcw %0" : "=m" (mode) : );
|
||||
mode = (mode & ~FPU_ROUND_MASK) | table[mode];
|
||||
asm ("fldcw %0" : : "m" (mode));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetPrecisionMode(u32 mode)
|
||||
{
|
||||
const char table[4] {
|
||||
0 << 8, // FPU_PREC_24
|
||||
2 << 8, // FPU_PREC_53
|
||||
3 << 8, // FPU_PREC_64
|
||||
3 << 8, // FPU_PREC_MASK
|
||||
};
|
||||
#ifdef _M_IX86
|
||||
// sets the floating-point lib to 53-bit
|
||||
// PowerPC has a 53bit floating pipeline only
|
||||
// eg: sscanf is very sensitive
|
||||
#ifdef _WIN32
|
||||
_control87(_PC_53, MCW_PC);
|
||||
#else
|
||||
unsigned short _mode;
|
||||
asm ("fstcw %0" : : "m" (_mode));
|
||||
_mode = (_mode & ~table[4]) | table[mode];
|
||||
asm ("fldcw %0" : : "m" (_mode));
|
||||
#endif
|
||||
#else
|
||||
//x64 doesn't need this - fpu is done with SSE
|
||||
//but still - set any useful sse options here
|
||||
#endif
|
||||
}
|
||||
void SetSIMDMode(u32 mode)
|
||||
{
|
||||
static const u32 ssetable[4] =
|
||||
{
|
||||
(0 << 13) | MASKS,
|
||||
(3 << 13) | MASKS,
|
||||
(2 << 13) | MASKS,
|
||||
(1 << 13) | MASKS,
|
||||
};
|
||||
u32 csr = ssetable[mode];
|
||||
_mm_setcsr(csr);
|
||||
}
|
||||
|
||||
void SaveSIMDState()
|
||||
{
|
||||
saved_sse_state = _mm_getcsr();
|
||||
}
|
||||
void LoadSIMDState()
|
||||
{
|
||||
_mm_setcsr(saved_sse_state);
|
||||
}
|
||||
void LoadDefaultSIMDState()
|
||||
{
|
||||
_mm_setcsr(default_sse_state);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
#ifndef _FIFO_QUEUE_H_
|
||||
#define _FIFO_QUEUE_H_
|
||||
|
||||
// a simple lockless thread-safe,
|
||||
// single reader, single writer queue
|
||||
|
||||
#include "Atomics.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
class FifoQueue
|
||||
{
|
||||
public:
|
||||
FifoQueue() : m_size(0)
|
||||
{
|
||||
m_write_ptr = m_read_ptr = new ElementPtr();
|
||||
}
|
||||
|
||||
~FifoQueue()
|
||||
{
|
||||
// this will empty out the whole queue
|
||||
delete m_read_ptr;
|
||||
}
|
||||
|
||||
u32 Size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
//return (m_read_ptr == m_write_ptr);
|
||||
return (0 == m_size);
|
||||
}
|
||||
|
||||
const T& Front() const
|
||||
{
|
||||
return *m_read_ptr->current;
|
||||
}
|
||||
|
||||
void Push(const T& t)
|
||||
{
|
||||
// create the element, add it to the queue
|
||||
m_write_ptr->current = new T(t);
|
||||
// set the next pointer to a new element ptr
|
||||
// then advance the write pointer
|
||||
m_write_ptr = m_write_ptr->next = new ElementPtr();
|
||||
Common::AtomicIncrement(m_size);
|
||||
}
|
||||
|
||||
void Pop()
|
||||
{
|
||||
Common::AtomicDecrement(m_size);
|
||||
ElementPtr *const tmpptr = m_read_ptr;
|
||||
// advance the read pointer
|
||||
m_read_ptr = m_read_ptr->next;
|
||||
// set the next element to NULL to stop the recursive deletion
|
||||
tmpptr->next = NULL;
|
||||
delete tmpptr; // this also deletes the element
|
||||
}
|
||||
|
||||
bool Pop(T& t)
|
||||
{
|
||||
if (Empty())
|
||||
return false;
|
||||
|
||||
t = Front();
|
||||
Pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// not thread-safe
|
||||
void Clear()
|
||||
{
|
||||
m_size = 0;
|
||||
delete m_read_ptr;
|
||||
m_write_ptr = m_read_ptr = new ElementPtr();
|
||||
}
|
||||
|
||||
private:
|
||||
// stores a pointer to element
|
||||
// and a pointer to the next ElementPtr
|
||||
class ElementPtr
|
||||
{
|
||||
public:
|
||||
ElementPtr() : current(NULL), next(NULL) {}
|
||||
|
||||
~ElementPtr()
|
||||
{
|
||||
if (current)
|
||||
{
|
||||
delete current;
|
||||
// recusion ftw
|
||||
if (next)
|
||||
delete next;
|
||||
}
|
||||
}
|
||||
|
||||
T *volatile current;
|
||||
ElementPtr *volatile next;
|
||||
};
|
||||
|
||||
ElementPtr *volatile m_write_ptr;
|
||||
ElementPtr *volatile m_read_ptr;
|
||||
volatile u32 m_size;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,121 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "CommonPaths.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// strcasecmp
|
||||
#ifdef __APPLE__
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "FileSearch.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
|
||||
|
||||
CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories)
|
||||
{
|
||||
// Reverse the loop order for speed?
|
||||
for (size_t j = 0; j < _rSearchStrings.size(); j++)
|
||||
{
|
||||
for (size_t i = 0; i < _rDirectories.size(); i++)
|
||||
{
|
||||
FindFiles(_rSearchStrings[j], _rDirectories[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath)
|
||||
{
|
||||
std::string GCMSearchPath;
|
||||
BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
|
||||
#ifdef _WIN32
|
||||
WIN32_FIND_DATA findData;
|
||||
HANDLE FindFirst = FindFirstFile(GCMSearchPath.c_str(), &findData);
|
||||
|
||||
if (FindFirst != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
bool bkeepLooping = true;
|
||||
|
||||
while (bkeepLooping)
|
||||
{
|
||||
if (findData.cFileName[0] != '.')
|
||||
{
|
||||
std::string strFilename;
|
||||
BuildCompleteFilename(strFilename, _strPath, findData.cFileName);
|
||||
m_FileNames.push_back(strFilename);
|
||||
}
|
||||
|
||||
bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false;
|
||||
}
|
||||
}
|
||||
FindClose(FindFirst);
|
||||
|
||||
|
||||
#else
|
||||
size_t dot_pos = _searchString.rfind(".");
|
||||
|
||||
if (dot_pos == std::string::npos)
|
||||
return;
|
||||
|
||||
std::string ext = _searchString.substr(dot_pos);
|
||||
DIR* dir = opendir(_strPath.c_str());
|
||||
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
dirent* dp;
|
||||
|
||||
while (true)
|
||||
{
|
||||
dp = readdir(dir);
|
||||
|
||||
if (!dp)
|
||||
break;
|
||||
|
||||
std::string s(dp->d_name);
|
||||
|
||||
if ( (!ext.compare(".*") && s.compare(".") && s.compare("..")) ||
|
||||
((s.size() > ext.size()) && (!strcasecmp(s.substr(s.size() - ext.size()).c_str(), ext.c_str())) ))
|
||||
{
|
||||
std::string full_name;
|
||||
if (strchr(DIR_SEP_CHRS, _strPath.c_str()[_strPath.size()-1]))
|
||||
full_name = _strPath + s;
|
||||
else
|
||||
full_name = _strPath + DIR_SEP + s;
|
||||
|
||||
m_FileNames.push_back(full_name);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const CFileSearch::XStringVector& CFileSearch::GetFileNames() const
|
||||
{
|
||||
return m_FileNames;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _FILESEARCH_H_
|
||||
#define _FILESEARCH_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CFileSearch
|
||||
{
|
||||
public:
|
||||
typedef std::vector<std::string>XStringVector;
|
||||
|
||||
CFileSearch(const XStringVector& _rSearchStrings, const XStringVector& _rDirectories);
|
||||
const XStringVector& GetFileNames() const;
|
||||
|
||||
private:
|
||||
|
||||
void FindFiles(const std::string& _searchString, const std::string& _strPath);
|
||||
|
||||
XStringVector m_FileNames;
|
||||
};
|
||||
|
||||
#endif // _FILESEARCH_H_
|
||||
|
|
@ -0,0 +1,880 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "CommonPaths.h"
|
||||
#include "FileUtil.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h> // for SHGetFolderPath
|
||||
#include <shellapi.h>
|
||||
#include <commdlg.h> // for GetSaveFileName
|
||||
#include <io.h>
|
||||
#include <direct.h> // getcwd
|
||||
#else
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#include <CoreFoundation/CFURL.h>
|
||||
#include <CoreFoundation/CFBundle.h>
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
#if !defined(__linux__) && !defined(_WIN32) && !defined(__QNX__)
|
||||
#define stat64 stat
|
||||
#define fstat64 fstat
|
||||
#endif
|
||||
|
||||
// Hack
|
||||
#if defined(__SYMBIAN32__)
|
||||
static inline int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
|
||||
struct dirent *readdir_entry;
|
||||
|
||||
readdir_entry = readdir(dirp);
|
||||
if (readdir_entry == NULL) {
|
||||
*result = NULL;
|
||||
return errno;
|
||||
}
|
||||
|
||||
*entry = *readdir_entry;
|
||||
*result = entry;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// This namespace has various generic functions related to files and paths.
|
||||
// The code still needs a ton of cleanup.
|
||||
// REMEMBER: strdup considered harmful!
|
||||
namespace File
|
||||
{
|
||||
|
||||
// Remove any ending forward slashes from directory paths
|
||||
// Modifies argument.
|
||||
static void StripTailDirSlashes(std::string &fname)
|
||||
{
|
||||
if (fname.length() > 1)
|
||||
{
|
||||
size_t i = fname.length() - 1;
|
||||
while (strchr(DIR_SEP_CHRS, fname[i]))
|
||||
fname[i--] = '\0';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns true if file filename exists
|
||||
bool Exists(const std::string &filename)
|
||||
{
|
||||
struct stat64 file_info;
|
||||
|
||||
std::string copy(filename);
|
||||
StripTailDirSlashes(copy);
|
||||
|
||||
int result = stat64(copy.c_str(), &file_info);
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
// Returns true if filename is a directory
|
||||
bool IsDirectory(const std::string &filename)
|
||||
{
|
||||
struct stat64 file_info;
|
||||
|
||||
std::string copy(filename);
|
||||
StripTailDirSlashes(copy);
|
||||
|
||||
int result = stat64(copy.c_str(), &file_info);
|
||||
|
||||
if (result < 0) {
|
||||
WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
return S_ISDIR(file_info.st_mode);
|
||||
}
|
||||
|
||||
// Deletes a given filename, return true on success
|
||||
// Doesn't supports deleting a directory
|
||||
bool Delete(const std::string &filename)
|
||||
{
|
||||
INFO_LOG(COMMON, "Delete: file %s", filename.c_str());
|
||||
|
||||
// Return true because we care about the file no
|
||||
// being there, not the actual delete.
|
||||
if (!Exists(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "Delete: %s does not exists", filename.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can't delete a directory
|
||||
if (IsDirectory(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!DeleteFile(filename.c_str()))
|
||||
{
|
||||
WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (unlink(filename.c_str()) == -1) {
|
||||
WARN_LOG(COMMON, "Delete: unlink failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string &path)
|
||||
{
|
||||
INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
|
||||
#ifdef _WIN32
|
||||
if (::CreateDirectory(path.c_str(), NULL))
|
||||
return true;
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str());
|
||||
return true;
|
||||
}
|
||||
ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error);
|
||||
return false;
|
||||
#else
|
||||
#ifdef BLACKBERRY
|
||||
if (mkdir(path.c_str(), 0775) == 0)
|
||||
#else
|
||||
if (mkdir(path.c_str(), 0755) == 0)
|
||||
#endif
|
||||
return true;
|
||||
|
||||
int err = errno;
|
||||
|
||||
if (err == EEXIST)
|
||||
{
|
||||
WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const std::string &fullPath)
|
||||
{
|
||||
int panicCounter = 100;
|
||||
INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str());
|
||||
|
||||
if (File::Exists(fullPath))
|
||||
{
|
||||
INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t position = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Skip the drive letter, no need to create C:\.
|
||||
position = 3;
|
||||
#endif
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Find next sub path
|
||||
position = fullPath.find_first_of(DIR_SEP_CHRS, position);
|
||||
|
||||
// we're done, yay!
|
||||
if (position == fullPath.npos)
|
||||
{
|
||||
if (!File::Exists(fullPath))
|
||||
File::CreateDir(fullPath);
|
||||
return true;
|
||||
}
|
||||
std::string subPath = fullPath.substr(0, position);
|
||||
if (!File::Exists(subPath))
|
||||
File::CreateDir(subPath);
|
||||
|
||||
// A safety check
|
||||
panicCounter--;
|
||||
if (panicCounter <= 0)
|
||||
{
|
||||
ERROR_LOG(COMMON, "CreateFullPath: directory structure too deep");
|
||||
return false;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Deletes a directory filename, returns true on success
|
||||
bool DeleteDir(const std::string &filename)
|
||||
{
|
||||
INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str());
|
||||
|
||||
// check if a directory
|
||||
if (!File::IsDirectory(filename))
|
||||
{
|
||||
ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (::RemoveDirectory(filename.c_str()))
|
||||
return true;
|
||||
#else
|
||||
if (rmdir(filename.c_str()) == 0)
|
||||
return true;
|
||||
#endif
|
||||
ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
bool Rename(const std::string &srcFilename, const std::string &destFilename)
|
||||
{
|
||||
INFO_LOG(COMMON, "Rename: %s --> %s",
|
||||
srcFilename.c_str(), destFilename.c_str());
|
||||
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
|
||||
return true;
|
||||
ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
||||
{
|
||||
INFO_LOG(COMMON, "Copy: %s --> %s",
|
||||
srcFilename.c_str(), destFilename.c_str());
|
||||
#ifdef _WIN32
|
||||
if (CopyFile(srcFilename.c_str(), destFilename.c_str(), FALSE))
|
||||
return true;
|
||||
|
||||
ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
#else
|
||||
|
||||
// buffer size
|
||||
#define BSIZE 1024
|
||||
|
||||
char buffer[BSIZE];
|
||||
|
||||
// Open input file
|
||||
FILE *input = fopen(srcFilename.c_str(), "rb");
|
||||
if (!input)
|
||||
{
|
||||
ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
// open output file
|
||||
FILE *output = fopen(destFilename.c_str(), "wb");
|
||||
if (!output)
|
||||
{
|
||||
fclose(input);
|
||||
ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy loop
|
||||
while (!feof(input))
|
||||
{
|
||||
// read input
|
||||
int rnum = fread(buffer, sizeof(char), BSIZE, input);
|
||||
if (rnum != BSIZE)
|
||||
{
|
||||
if (ferror(input) != 0)
|
||||
{
|
||||
ERROR_LOG(COMMON,
|
||||
"Copy: failed reading from source, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// write output
|
||||
int wnum = fwrite(buffer, sizeof(char), rnum, output);
|
||||
if (wnum != rnum)
|
||||
{
|
||||
ERROR_LOG(COMMON,
|
||||
"Copy: failed writing to output, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// close flushs
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
tm GetModifTime(const std::string &filename)
|
||||
{
|
||||
tm return_time = {0};
|
||||
if (!Exists(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "GetCreateTime: failed %s: No such file", filename.c_str());
|
||||
return return_time;
|
||||
}
|
||||
|
||||
if (IsDirectory(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "GetCreateTime: failed %s: is a directory", filename.c_str());
|
||||
return return_time;
|
||||
}
|
||||
struct stat64 buf;
|
||||
if (stat64(filename.c_str(), &buf) == 0)
|
||||
{
|
||||
DEBUG_LOG(COMMON, "GetCreateTime: %s: %lld",
|
||||
filename.c_str(), (long long)buf.st_mtime);
|
||||
localtime_r((time_t*)&buf.st_mtime,&return_time);
|
||||
return return_time;
|
||||
}
|
||||
|
||||
ERROR_LOG(COMMON, "GetCreateTime: Stat failed %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
return return_time;
|
||||
}
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string &filename)
|
||||
{
|
||||
if (!Exists(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IsDirectory(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
struct stat64 buf;
|
||||
if (stat64(filename.c_str(), &buf) == 0)
|
||||
{
|
||||
DEBUG_LOG(COMMON, "GetSize: %s: %lld",
|
||||
filename.c_str(), (long long)buf.st_size);
|
||||
return buf.st_size;
|
||||
}
|
||||
|
||||
ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Overloaded GetSize, accepts file descriptor
|
||||
u64 GetSize(const int fd)
|
||||
{
|
||||
struct stat64 buf;
|
||||
if (fstat64(fd, &buf) != 0) {
|
||||
ERROR_LOG(COMMON, "GetSize: stat failed %i: %s",
|
||||
fd, GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
return buf.st_size;
|
||||
}
|
||||
|
||||
// Overloaded GetSize, accepts FILE*
|
||||
u64 GetSize(FILE *f)
|
||||
{
|
||||
// can't use off_t here because it can be 32-bit
|
||||
u64 pos = ftello(f);
|
||||
if (fseeko(f, 0, SEEK_END) != 0) {
|
||||
ERROR_LOG(COMMON, "GetSize: seek failed %p: %s",
|
||||
f, GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
u64 size = ftello(f);
|
||||
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
|
||||
ERROR_LOG(COMMON, "GetSize: seek failed %p: %s",
|
||||
f, GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const std::string &filename)
|
||||
{
|
||||
INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
|
||||
|
||||
FILE *pFile = fopen(filename.c_str(), "wb");
|
||||
if (!pFile) {
|
||||
ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
fclose(pFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Scans the directory tree gets, starting from _Directory and adds the
|
||||
// results into parentEntry. Returns the number of files+directories found
|
||||
u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
|
||||
{
|
||||
INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str());
|
||||
// How many files + directories we found
|
||||
u32 foundEntries = 0;
|
||||
#ifdef _WIN32
|
||||
// Find the first file in the directory.
|
||||
WIN32_FIND_DATA ffd;
|
||||
|
||||
HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(hFind);
|
||||
return foundEntries;
|
||||
}
|
||||
// windows loop
|
||||
do
|
||||
{
|
||||
FSTEntry entry;
|
||||
const std::string virtualName(ffd.cFileName);
|
||||
#else
|
||||
struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
|
||||
struct dirent_large diren;
|
||||
struct dirent *result = NULL;
|
||||
|
||||
DIR *dirp = opendir(directory.c_str());
|
||||
if (!dirp)
|
||||
return 0;
|
||||
|
||||
// non windows loop
|
||||
while (!readdir_r(dirp, (dirent*)&diren, &result) && result)
|
||||
{
|
||||
FSTEntry entry;
|
||||
const std::string virtualName(result->d_name);
|
||||
#endif
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
||||
(virtualName[2] == '\0')))
|
||||
continue;
|
||||
entry.virtualName = virtualName;
|
||||
entry.physicalName = directory;
|
||||
entry.physicalName += DIR_SEP + entry.virtualName;
|
||||
|
||||
if (IsDirectory(entry.physicalName.c_str()))
|
||||
{
|
||||
entry.isDirectory = true;
|
||||
// is a directory, lets go inside
|
||||
entry.size = ScanDirectoryTree(entry.physicalName, entry);
|
||||
foundEntries += (u32)entry.size;
|
||||
}
|
||||
else
|
||||
{ // is a file
|
||||
entry.isDirectory = false;
|
||||
entry.size = GetSize(entry.physicalName.c_str());
|
||||
}
|
||||
++foundEntries;
|
||||
// Push into the tree
|
||||
parentEntry.children.push_back(entry);
|
||||
#ifdef _WIN32
|
||||
} while (FindNextFile(hFind, &ffd) != 0);
|
||||
FindClose(hFind);
|
||||
#else
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
// Return number of entries found.
|
||||
return foundEntries;
|
||||
}
|
||||
|
||||
|
||||
// Deletes the given directory and anything under it. Returns true on success.
|
||||
bool DeleteDirRecursively(const std::string &directory)
|
||||
{
|
||||
INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str());
|
||||
#ifdef _WIN32
|
||||
// Find the first file in the directory.
|
||||
WIN32_FIND_DATA ffd;
|
||||
HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(hFind);
|
||||
return false;
|
||||
}
|
||||
|
||||
// windows loop
|
||||
do
|
||||
{
|
||||
const std::string virtualName = ffd.cFileName;
|
||||
#else
|
||||
struct dirent dirent, *result = NULL;
|
||||
DIR *dirp = opendir(directory.c_str());
|
||||
if (!dirp)
|
||||
return false;
|
||||
|
||||
// non windows loop
|
||||
while (!readdir_r(dirp, &dirent, &result) && result)
|
||||
{
|
||||
const std::string virtualName = result->d_name;
|
||||
#endif
|
||||
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
||||
(virtualName[2] == '\0')))
|
||||
continue;
|
||||
|
||||
std::string newPath = directory + DIR_SEP + virtualName;
|
||||
if (IsDirectory(newPath))
|
||||
{
|
||||
if (!DeleteDirRecursively(newPath))
|
||||
{
|
||||
#ifndef _WIN32
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File::Delete(newPath))
|
||||
{
|
||||
#ifndef _WIN32
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
} while (FindNextFile(hFind, &ffd) != 0);
|
||||
FindClose(hFind);
|
||||
#else
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
File::DeleteDir(directory);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string &source_path, const std::string &dest_path)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
if (source_path == dest_path) return;
|
||||
if (!File::Exists(source_path)) return;
|
||||
if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);
|
||||
|
||||
struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
|
||||
struct dirent_large diren;
|
||||
struct dirent *result = NULL;
|
||||
DIR *dirp = opendir(source_path.c_str());
|
||||
if (!dirp) return;
|
||||
|
||||
while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
|
||||
{
|
||||
const std::string virtualName(result->d_name);
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
||||
(virtualName[2] == '\0')))
|
||||
continue;
|
||||
|
||||
std::string source, dest;
|
||||
source = source_path + virtualName;
|
||||
dest = dest_path + virtualName;
|
||||
if (IsDirectory(source))
|
||||
{
|
||||
source += '/';
|
||||
dest += '/';
|
||||
if (!File::Exists(dest)) File::CreateFullPath(dest);
|
||||
CopyDir(source, dest);
|
||||
}
|
||||
else if (!File::Exists(dest)) File::Copy(source, dest);
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns the current directory
|
||||
std::string GetCurrentDir()
|
||||
{
|
||||
char *dir;
|
||||
// Get the current working directory (getcwd uses malloc)
|
||||
if (!(dir = __getcwd(NULL, 0))) {
|
||||
|
||||
ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s",
|
||||
GetLastErrorMsg());
|
||||
return NULL;
|
||||
}
|
||||
std::string strDir = dir;
|
||||
free(dir);
|
||||
return strDir;
|
||||
}
|
||||
|
||||
// Sets the current directory to the given directory
|
||||
bool SetCurrentDir(const std::string &directory)
|
||||
{
|
||||
return __chdir(directory.c_str()) == 0;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
std::string GetBundleDirectory()
|
||||
{
|
||||
CFURLRef BundleRef;
|
||||
char AppBundlePath[MAXPATHLEN];
|
||||
// Get the main bundle for the app
|
||||
BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
||||
CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle);
|
||||
CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath));
|
||||
CFRelease(BundleRef);
|
||||
CFRelease(BundlePath);
|
||||
|
||||
return AppBundlePath;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string &GetExeDirectory()
|
||||
{
|
||||
static std::string DolphinPath;
|
||||
if (DolphinPath.empty())
|
||||
{
|
||||
char Dolphin_exe_Path[2048];
|
||||
GetModuleFileNameA(NULL, Dolphin_exe_Path, 2048);
|
||||
DolphinPath = Dolphin_exe_Path;
|
||||
DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
|
||||
}
|
||||
return DolphinPath;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string GetSysDirectory()
|
||||
{
|
||||
std::string sysDir;
|
||||
|
||||
#if defined (__APPLE__)
|
||||
sysDir = GetBundleDirectory();
|
||||
sysDir += DIR_SEP;
|
||||
sysDir += SYSDATA_DIR;
|
||||
#else
|
||||
sysDir = SYSDATA_DIR;
|
||||
#endif
|
||||
sysDir += DIR_SEP;
|
||||
|
||||
INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str());
|
||||
return sysDir;
|
||||
}
|
||||
|
||||
// Returns a string with a Dolphin data dir or file in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
||||
{
|
||||
static std::string paths[NUM_PATH_INDICES];
|
||||
|
||||
// Set up all paths and files on the first run
|
||||
if (paths[D_USER_IDX].empty())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// TODO: use GetExeDirectory() here instead of ROOT_DIR so that if the cwd is changed we still have the correct paths?
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
#elif defined(__SYMBIAN32__)
|
||||
paths[D_USER_IDX] = "E:" DIR_SEP "PPSSPP" DIR_SEP;
|
||||
#else
|
||||
if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
else
|
||||
paths[D_USER_IDX] = std::string(getenv("HOME")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP;
|
||||
#endif
|
||||
INFO_LOG(COMMON, "GetUserPath: Setting user directory to %s:", paths[D_USER_IDX].c_str());
|
||||
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
|
||||
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
|
||||
paths[F_CONFIG_IDX] = paths[D_CONFIG_IDX] + CONFIG_FILE;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
}
|
||||
|
||||
return paths[DirIDX];
|
||||
}
|
||||
|
||||
bool WriteStringToFile(bool text_file, const std::string &str, const char *filename)
|
||||
{
|
||||
FILE *f = fopen(filename, text_file ? "w" : "wb");
|
||||
if (!f)
|
||||
return false;
|
||||
size_t len = str.size();
|
||||
if (len != fwrite(str.data(), 1, str.size(), f)) // TODO: string::data() may not be contiguous
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFileToString(bool text_file, const char *filename, std::string &str)
|
||||
{
|
||||
FILE *f = fopen(filename, text_file ? "r" : "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
size_t len = (size_t)GetSize(f);
|
||||
char *buf = new char[len + 1];
|
||||
buf[fread(buf, 1, len, f)] = 0;
|
||||
str = std::string(buf, len);
|
||||
fclose(f);
|
||||
delete [] buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
IOFile::IOFile()
|
||||
: m_file(NULL), m_good(true)
|
||||
{}
|
||||
|
||||
IOFile::IOFile(std::FILE* file)
|
||||
: m_file(file), m_good(true)
|
||||
{}
|
||||
|
||||
IOFile::IOFile(const std::string& filename, const char openmode[])
|
||||
: m_file(NULL), m_good(true)
|
||||
{
|
||||
Open(filename, openmode);
|
||||
}
|
||||
|
||||
IOFile::~IOFile()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool IOFile::Open(const std::string& filename, const char openmode[])
|
||||
{
|
||||
Close();
|
||||
#ifdef _WIN32
|
||||
fopen_s(&m_file, filename.c_str(), openmode);
|
||||
#else
|
||||
m_file = fopen(filename.c_str(), openmode);
|
||||
#endif
|
||||
|
||||
m_good = IsOpen();
|
||||
return m_good;
|
||||
}
|
||||
|
||||
bool IOFile::Close()
|
||||
{
|
||||
if (!IsOpen() || 0 != std::fclose(m_file))
|
||||
m_good = false;
|
||||
|
||||
m_file = NULL;
|
||||
return m_good;
|
||||
}
|
||||
|
||||
std::FILE* IOFile::ReleaseHandle()
|
||||
{
|
||||
std::FILE* const ret = m_file;
|
||||
m_file = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void IOFile::SetHandle(std::FILE* file)
|
||||
{
|
||||
Close();
|
||||
Clear();
|
||||
m_file = file;
|
||||
}
|
||||
|
||||
u64 IOFile::GetSize()
|
||||
{
|
||||
if (IsOpen())
|
||||
return File::GetSize(m_file);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IOFile::Seek(s64 off, int origin)
|
||||
{
|
||||
if (!IsOpen() || 0 != fseeko(m_file, off, origin))
|
||||
m_good = false;
|
||||
|
||||
return m_good;
|
||||
}
|
||||
|
||||
u64 IOFile::Tell()
|
||||
{
|
||||
if (IsOpen())
|
||||
return ftello(m_file);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IOFile::Flush()
|
||||
{
|
||||
if (!IsOpen() || 0 != std::fflush(m_file))
|
||||
m_good = false;
|
||||
|
||||
return m_good;
|
||||
}
|
||||
|
||||
bool IOFile::Resize(u64 size)
|
||||
{
|
||||
if (!IsOpen() || 0 !=
|
||||
#ifdef _WIN32
|
||||
// ector: _chsize sucks, not 64-bit safe
|
||||
// F|RES: changed to _chsize_s. i think it is 64-bit safe
|
||||
_chsize_s(_fileno(m_file), size)
|
||||
#else
|
||||
// TODO: handle 64bit and growing
|
||||
ftruncate(fileno(m_file), size)
|
||||
#endif
|
||||
)
|
||||
m_good = false;
|
||||
|
||||
return m_good;
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,214 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _FILEUTIL_H_
|
||||
#define _FILEUTIL_H_
|
||||
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
// User directory indices for GetUserPath
|
||||
enum {
|
||||
D_USER_IDX,
|
||||
D_SCREENSHOTS_IDX,
|
||||
D_LOGS_IDX,
|
||||
D_CONFIG_IDX,
|
||||
F_CONFIG_IDX,
|
||||
F_MAINLOG_IDX,
|
||||
NUM_PATH_INDICES
|
||||
};
|
||||
|
||||
// No thread safe
|
||||
#ifdef _WIN32
|
||||
inline struct tm* localtime_r (const time_t *clock, struct tm *result) {
|
||||
if (!clock || !result) return NULL;
|
||||
memcpy(result,localtime(clock),sizeof(*result));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace File
|
||||
{
|
||||
|
||||
// FileSystem tree node/
|
||||
struct FSTEntry
|
||||
{
|
||||
bool isDirectory;
|
||||
u64 size; // file length or number of entries from children
|
||||
std::string physicalName; // name on disk
|
||||
std::string virtualName; // name in FST names table
|
||||
std::vector<FSTEntry> children;
|
||||
};
|
||||
|
||||
// Returns true if file filename exists
|
||||
bool Exists(const std::string &filename);
|
||||
|
||||
// Returns true if filename is a directory
|
||||
bool IsDirectory(const std::string &filename);
|
||||
|
||||
// Returns struct with modification date of file
|
||||
tm GetModifTime(const std::string &filename);
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string &filename);
|
||||
|
||||
// Overloaded GetSize, accepts file descriptor
|
||||
u64 GetSize(const int fd);
|
||||
|
||||
// Overloaded GetSize, accepts FILE*
|
||||
u64 GetSize(FILE *f);
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string &filename);
|
||||
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const std::string &fullPath);
|
||||
|
||||
// Deletes a given filename, return true on success
|
||||
// Doesn't supports deleting a directory
|
||||
bool Delete(const std::string &filename);
|
||||
|
||||
// Deletes a directory filename, returns true on success
|
||||
bool DeleteDir(const std::string &filename);
|
||||
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
bool Rename(const std::string &srcFilename, const std::string &destFilename);
|
||||
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
bool Copy(const std::string &srcFilename, const std::string &destFilename);
|
||||
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const std::string &filename);
|
||||
|
||||
// Scans the directory tree gets, starting from _Directory and adds the
|
||||
// results into parentEntry. Returns the number of files+directories found
|
||||
u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry);
|
||||
|
||||
// deletes the given directory and anything under it. Returns true on success.
|
||||
bool DeleteDirRecursively(const std::string &directory);
|
||||
|
||||
// Returns the current directory
|
||||
std::string GetCurrentDir();
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string &source_path, const std::string &dest_path);
|
||||
|
||||
// Set the current directory to given directory
|
||||
bool SetCurrentDir(const std::string &directory);
|
||||
|
||||
// Returns a pointer to a string with a Dolphin data dir in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
|
||||
|
||||
// Returns the path to where the sys file are
|
||||
std::string GetSysDirectory();
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::string GetBundleDirectory();
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string &GetExeDirectory();
|
||||
#endif
|
||||
|
||||
bool WriteStringToFile(bool text_file, const std::string &str, const char *filename);
|
||||
bool ReadFileToString(bool text_file, const char *filename, std::string &str);
|
||||
|
||||
// simple wrapper for cstdlib file functions to
|
||||
// hopefully will make error checking easier
|
||||
// and make forgetting an fclose() harder
|
||||
class IOFile : NonCopyable
|
||||
{
|
||||
public:
|
||||
IOFile();
|
||||
IOFile(std::FILE* file);
|
||||
IOFile(const std::string& filename, const char openmode[]);
|
||||
|
||||
~IOFile();
|
||||
|
||||
bool Open(const std::string& filename, const char openmode[]);
|
||||
bool Close();
|
||||
|
||||
template <typename T>
|
||||
bool ReadArray(T* data, size_t length)
|
||||
{
|
||||
if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file))
|
||||
m_good = false;
|
||||
|
||||
return m_good;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool WriteArray(const T* data, size_t length)
|
||||
{
|
||||
if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file))
|
||||
m_good = false;
|
||||
|
||||
return m_good;
|
||||
}
|
||||
|
||||
bool ReadBytes(void* data, size_t length)
|
||||
{
|
||||
return ReadArray(reinterpret_cast<char*>(data), length);
|
||||
}
|
||||
|
||||
bool WriteBytes(const void* data, size_t length)
|
||||
{
|
||||
return WriteArray(reinterpret_cast<const char*>(data), length);
|
||||
}
|
||||
|
||||
bool IsOpen() { return NULL != m_file; }
|
||||
|
||||
// m_good is set to false when a read, write or other function fails
|
||||
bool IsGood() { return m_good; }
|
||||
operator void*() { return m_good ? m_file : NULL; }
|
||||
|
||||
std::FILE* ReleaseHandle();
|
||||
|
||||
std::FILE* GetHandle() { return m_file; }
|
||||
|
||||
void SetHandle(std::FILE* file);
|
||||
|
||||
bool Seek(s64 off, int origin);
|
||||
u64 Tell();
|
||||
u64 GetSize();
|
||||
bool Resize(u64 size);
|
||||
bool Flush();
|
||||
|
||||
// clear error state
|
||||
void Clear() {
|
||||
m_good = true;
|
||||
#undef clearerr
|
||||
std::clearerr(m_file);
|
||||
}
|
||||
|
||||
private:
|
||||
IOFile& operator=(const IOFile&) /*= delete*/;
|
||||
|
||||
std::FILE* m_file;
|
||||
bool m_good;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
|
@ -0,0 +1,229 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _FIXED_SIZE_QUEUE_H_
|
||||
#define _FIXED_SIZE_QUEUE_H_
|
||||
|
||||
#include <cstring>
|
||||
#include "ChunkFile.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the
|
||||
// real STL classes.
|
||||
|
||||
// Not fully featured, no safety checking yet. Add features as needed.
|
||||
|
||||
template <class T, int N>
|
||||
class FixedSizeQueue {
|
||||
public:
|
||||
FixedSizeQueue() {
|
||||
// Allocate aligned memory, just because.
|
||||
//int sizeInBytes = N * sizeof(T);
|
||||
//storage_ = (T *)AllocateMemoryPages(sizeInBytes);
|
||||
storage_ = new T[N];
|
||||
clear();
|
||||
}
|
||||
|
||||
~FixedSizeQueue() {
|
||||
// FreeMemoryPages((void *)storage_, N * sizeof(T));
|
||||
delete [] storage_;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
head_ = 0;
|
||||
tail_ = 0;
|
||||
count_ = 0;
|
||||
}
|
||||
|
||||
void push(T t) {
|
||||
storage_[tail_] = t;
|
||||
tail_++;
|
||||
if (tail_ == N)
|
||||
tail_ = 0;
|
||||
count_++;
|
||||
}
|
||||
|
||||
// Gets pointers to write to directly.
|
||||
void pushPointers(size_t size, T **dest1, size_t *sz1, T **dest2, size_t *sz2) {
|
||||
if (tail_ + size < N) {
|
||||
*dest1 = &storage_[tail_];
|
||||
*sz1 = size;
|
||||
tail_ += (int)size;
|
||||
if (tail_ == N) tail_ = 0;
|
||||
*dest2 = 0;
|
||||
*sz2 = 0;
|
||||
} else {
|
||||
*dest1 = &storage_[tail_];
|
||||
*sz1 = N - tail_;
|
||||
tail_ = (int)(size - *sz1);
|
||||
*dest2 = &storage_[0];
|
||||
*sz2 = tail_;
|
||||
}
|
||||
count_ += (int)size;
|
||||
}
|
||||
|
||||
void popPointers(size_t size, const T **src1, size_t *sz1, const T **src2, size_t *sz2) {
|
||||
if (size > count_) size = count_;
|
||||
|
||||
if (head_ + size < N) {
|
||||
*src1 = &storage_[head_];
|
||||
*sz1 = size;
|
||||
head_ += (int)size;
|
||||
if (head_ == N) head_ = 0;
|
||||
*src2 = 0;
|
||||
*sz2 = 0;
|
||||
} else {
|
||||
*src1 = &storage_[head_];
|
||||
*sz1 = N - head_;
|
||||
head_ = (int)(size - *sz1);
|
||||
*src2 = &storage_[0];
|
||||
*sz2 = head_;
|
||||
}
|
||||
count_ -= (int)size;
|
||||
}
|
||||
|
||||
void pop() {
|
||||
head_++;
|
||||
if (head_ == N)
|
||||
head_ = 0;
|
||||
count_--;
|
||||
}
|
||||
|
||||
/*
|
||||
void push_array(const T *ptr, size_t num) {
|
||||
// TODO: memcpy
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
push(ptr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void pop_array(T *outptr, size_t num) {
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
outptr[i] = front();
|
||||
pop();
|
||||
}
|
||||
}*/
|
||||
|
||||
T pop_front() {
|
||||
const T &temp = storage_[head_];
|
||||
pop();
|
||||
return temp;
|
||||
}
|
||||
|
||||
T &front() { return storage_[head_]; }
|
||||
|
||||
const T &front() const { return storage_[head_]; }
|
||||
|
||||
size_t size() const {
|
||||
return count_;
|
||||
}
|
||||
|
||||
size_t capacity() const {
|
||||
return N;
|
||||
}
|
||||
|
||||
int room() const {
|
||||
return N - count_;
|
||||
}
|
||||
|
||||
bool empty() {
|
||||
return count_ == 0;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p) {
|
||||
int size = N;
|
||||
p.Do(size);
|
||||
if (size != N)
|
||||
{
|
||||
ERROR_LOG(HLE, "Savestate failure: Incompatible queue size.");
|
||||
return;
|
||||
}
|
||||
p.DoArray<T>(storage_, N);
|
||||
p.Do(head_);
|
||||
p.Do(tail_);
|
||||
p.Do(count_);
|
||||
p.DoMarker("FixedSizeQueue");
|
||||
}
|
||||
|
||||
private:
|
||||
T *storage_;
|
||||
int head_;
|
||||
int tail_;
|
||||
int count_; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future.
|
||||
|
||||
// Make copy constructor private for now.
|
||||
FixedSizeQueue(FixedSizeQueue &other) { }
|
||||
};
|
||||
|
||||
|
||||
// I'm not sure this is 100% safe but it might be "Good Enough" :)
|
||||
// TODO: Use this, maybe make it safer first by using proper atomics
|
||||
// instead of volatile
|
||||
template<class T, int blockSize, int numBlocks>
|
||||
class LockFreeBlockQueue {
|
||||
public:
|
||||
LockFreeBlockQueue() {
|
||||
curReadBlock = 0;
|
||||
curWriteBlock = 0;
|
||||
for (size_t i = 0; i < numBlocks; i++) {
|
||||
blocks[i] = new T[blockSize];
|
||||
}
|
||||
}
|
||||
~LockFreeBlockQueue() {
|
||||
for (size_t i = 0; i < numBlocks; i++) {
|
||||
delete [] blocks[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Write to the returned pointer then call EndPush to finish the push.
|
||||
T *BeginPush() {
|
||||
return blocks[curWriteBlock];
|
||||
}
|
||||
void EndPush() {
|
||||
curWriteBlock++;
|
||||
if (curWriteBlock == NUM_BLOCKS)
|
||||
curWriteBlock = 0;
|
||||
}
|
||||
|
||||
bool CanPush() {
|
||||
int nextBlock = curWriteBlock + 1;
|
||||
if (nextBlock == NUM_BLOCKS) nextBlock = 0;
|
||||
return nextBlock != curReadBlock;
|
||||
}
|
||||
|
||||
bool CanPop() { return curReadBlock != curWriteBlock; }
|
||||
|
||||
// Read from the returned pointer then call EndPush to finish the pop.
|
||||
T *BeginPop() {
|
||||
return blocks[curReadBlock];
|
||||
}
|
||||
T *EndPop() {
|
||||
curReadBlock++;
|
||||
if (curReadBlock == NUM_BLOCKS)
|
||||
curReadBlock = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
enum { NUM_BLOCKS = 16 };
|
||||
T **blocks[NUM_BLOCKS];
|
||||
|
||||
volatile int curReadBlock;
|
||||
volatile int curWriteBlock;
|
||||
};
|
||||
|
||||
#endif // _FIXED_SIZE_QUEUE_H_
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
// Really stupid but much faster than a vector for keeping breakpoints in
|
||||
// and looking them up in debug mode. STL is SOOO SLOW in debug mode on Windows.
|
||||
|
||||
|
||||
template<class T, size_t maxCount>
|
||||
class FixedSizeUnorderedSet
|
||||
{
|
||||
public:
|
||||
bool insert(T item)
|
||||
{
|
||||
if (count_ < (int)maxCount - 1)
|
||||
{
|
||||
data_[count_++] = item;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool remove(T item)
|
||||
{
|
||||
for (int i = 0; i < count_; i++)
|
||||
{
|
||||
if (data_[i] == item)
|
||||
{
|
||||
if (i == count_ - 1)
|
||||
{
|
||||
count_--;
|
||||
}
|
||||
else
|
||||
{
|
||||
data_[i] = data_[count_ - 1];
|
||||
count_--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return (size_t)count_;
|
||||
}
|
||||
|
||||
T &operator[](size_t index) {
|
||||
return data_[index];
|
||||
}
|
||||
|
||||
const T &operator[](size_t index) const {
|
||||
return data_[index];
|
||||
}
|
||||
|
||||
void clear() {
|
||||
count_ = 0;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return count_ != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
T data_[maxCount];
|
||||
int count_;
|
||||
};
|
|
@ -0,0 +1,535 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 <algorithm>
|
||||
#include "Hash.h"
|
||||
#if _M_SSE >= 0x402
|
||||
#include "CPUDetect.h"
|
||||
#include <nmmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows defines min/max which conflict with std::min/std::max.
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
static u64 (*ptrHashFunction)(const u8 *src, int len, u32 samples) = &GetMurmurHash3;
|
||||
|
||||
// uint32_t
|
||||
// WARNING - may read one more byte!
|
||||
// Implementation from Wikipedia.
|
||||
u32 HashFletcher(const u8* data_u8, size_t length)
|
||||
{
|
||||
const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */
|
||||
size_t len = (length + 1) / 2; /* Length in 16-bit words */
|
||||
u32 sum1 = 0xffff, sum2 = 0xffff;
|
||||
|
||||
while (len)
|
||||
{
|
||||
size_t tlen = len > 360 ? 360 : len;
|
||||
len -= tlen;
|
||||
|
||||
do {
|
||||
sum1 += *data++;
|
||||
sum2 += sum1;
|
||||
}
|
||||
while (--tlen);
|
||||
|
||||
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
||||
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
||||
}
|
||||
|
||||
// Second reduction step to reduce sums to 16 bits
|
||||
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
||||
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
||||
return(sum2 << 16 | sum1);
|
||||
}
|
||||
|
||||
|
||||
// Implementation from Wikipedia
|
||||
// Slightly slower than Fletcher above, but slighly more reliable.
|
||||
#define MOD_ADLER 65521
|
||||
// data: Pointer to the data to be summed; len is in bytes
|
||||
u32 HashAdler32(const u8* data, size_t len)
|
||||
{
|
||||
u32 a = 1, b = 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
size_t tlen = len > 5550 ? 5550 : len;
|
||||
len -= tlen;
|
||||
|
||||
do
|
||||
{
|
||||
a += *data++;
|
||||
b += a;
|
||||
}
|
||||
while (--tlen);
|
||||
|
||||
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
|
||||
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
|
||||
}
|
||||
|
||||
// It can be shown that a <= 0x1013a here, so a single subtract will do.
|
||||
if (a >= MOD_ADLER)
|
||||
{
|
||||
a -= MOD_ADLER;
|
||||
}
|
||||
|
||||
// It can be shown that b can reach 0xfff87 here.
|
||||
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
|
||||
|
||||
if (b >= MOD_ADLER)
|
||||
{
|
||||
b -= MOD_ADLER;
|
||||
}
|
||||
|
||||
return((b << 16) | a);
|
||||
}
|
||||
|
||||
// Stupid hash - but can't go back now :)
|
||||
// Don't use for new things. At least it's reasonably fast.
|
||||
u32 HashEctor(const u8* ptr, int length)
|
||||
{
|
||||
u32 crc = 0;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
crc ^= ptr[i];
|
||||
crc = (crc << 3) | (crc >> 29);
|
||||
}
|
||||
|
||||
return(crc);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _M_X64
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
|
||||
inline u64 getblock(const u64 * p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//----------
|
||||
// Block mix - combine the key bits with the hash bits and scramble everything
|
||||
|
||||
inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2)
|
||||
{
|
||||
k1 *= c1;
|
||||
k1 = __rotl64(k1,23);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
h1 += h2;
|
||||
|
||||
h2 = __rotl64(h2,41);
|
||||
|
||||
k2 *= c2;
|
||||
k2 = __rotl64(k2,23);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = h1*3+0x52dce729;
|
||||
h2 = h2*3+0x38495ab5;
|
||||
|
||||
c1 = c1*5+0x7b7d159c;
|
||||
c2 = c2*5+0x6bce6396;
|
||||
}
|
||||
|
||||
//----------
|
||||
// Finalization mix - avalanches all bits to within 0.05% bias
|
||||
|
||||
inline u64 fmix64(u64 k)
|
||||
{
|
||||
k ^= k >> 33;
|
||||
k *= 0xff51afd7ed558ccd;
|
||||
k ^= k >> 33;
|
||||
k *= 0xc4ceb9fe1a85ec53;
|
||||
k ^= k >> 33;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
u64 GetMurmurHash3(const u8 *src, int len, u32 samples)
|
||||
{
|
||||
const u8 * data = (const u8*)src;
|
||||
const int nblocks = len / 16;
|
||||
u32 Step = (len / 8);
|
||||
if(samples == 0) samples = std::max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
|
||||
u64 h1 = 0x9368e53c2f6af274;
|
||||
u64 h2 = 0x586dcd208f7cd3fd;
|
||||
|
||||
u64 c1 = 0x87c37b91114253d5;
|
||||
u64 c2 = 0x4cf5ad432745937f;
|
||||
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const u64 * blocks = (const u64 *)(data);
|
||||
|
||||
for(int i = 0; i < nblocks; i+=Step)
|
||||
{
|
||||
u64 k1 = getblock(blocks,i*2+0);
|
||||
u64 k2 = getblock(blocks,i*2+1);
|
||||
|
||||
bmix64(h1,h2,k1,k2,c1,c2);
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const u8 * tail = (const u8*)(data + nblocks*16);
|
||||
|
||||
u64 k1 = 0;
|
||||
u64 k2 = 0;
|
||||
|
||||
switch(len & 15)
|
||||
{
|
||||
case 15: k2 ^= u64(tail[14]) << 48;
|
||||
case 14: k2 ^= u64(tail[13]) << 40;
|
||||
case 13: k2 ^= u64(tail[12]) << 32;
|
||||
case 12: k2 ^= u64(tail[11]) << 24;
|
||||
case 11: k2 ^= u64(tail[10]) << 16;
|
||||
case 10: k2 ^= u64(tail[ 9]) << 8;
|
||||
case 9: k2 ^= u64(tail[ 8]) << 0;
|
||||
|
||||
case 8: k1 ^= u64(tail[ 7]) << 56;
|
||||
case 7: k1 ^= u64(tail[ 6]) << 48;
|
||||
case 6: k1 ^= u64(tail[ 5]) << 40;
|
||||
case 5: k1 ^= u64(tail[ 4]) << 32;
|
||||
case 4: k1 ^= u64(tail[ 3]) << 24;
|
||||
case 3: k1 ^= u64(tail[ 2]) << 16;
|
||||
case 2: k1 ^= u64(tail[ 1]) << 8;
|
||||
case 1: k1 ^= u64(tail[ 0]) << 0;
|
||||
bmix64(h1,h2,k1,k2,c1,c2);
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix64(h1);
|
||||
h2 = fmix64(h2);
|
||||
|
||||
h1 += h2;
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
|
||||
// CRC32 hash using the SSE4.2 instruction
|
||||
u64 GetCRC32(const u8 *src, int len, u32 samples)
|
||||
{
|
||||
#if _M_SSE >= 0x402
|
||||
u64 h = len;
|
||||
u32 Step = (len / 8);
|
||||
const u64 *data = (const u64 *)src;
|
||||
const u64 *end = data + Step;
|
||||
if(samples == 0) samples = std::max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
while(data < end)
|
||||
{
|
||||
h = _mm_crc32_u64(h, data[0]);
|
||||
data += Step;
|
||||
}
|
||||
|
||||
const u8 *data2 = (const u8*)end;
|
||||
return _mm_crc32_u64(h, u64(data2[0]));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* NOTE: This hash function is used for custom texture loading/dumping, so
|
||||
it should not be changed, which would require all custom textures to be
|
||||
recalculated for their new hash values. If the hashing function is
|
||||
changed, make sure this one is still used when the legacy parameter is
|
||||
true. */
|
||||
u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
|
||||
{
|
||||
const u64 m = 0xc6a4a7935bd1e995;
|
||||
u64 h = len * m;
|
||||
const int r = 47;
|
||||
u32 Step = (len / 8);
|
||||
const u64 *data = (const u64 *)src;
|
||||
const u64 *end = data + Step;
|
||||
if(samples == 0) samples = std::max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
while(data < end)
|
||||
{
|
||||
u64 k = data[0];
|
||||
data+=Step;
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
h ^= k;
|
||||
h *= m;
|
||||
}
|
||||
|
||||
const u8 * data2 = (const u8*)end;
|
||||
|
||||
switch(len & 7)
|
||||
{
|
||||
case 7: h ^= u64(data2[6]) << 48;
|
||||
case 6: h ^= u64(data2[5]) << 40;
|
||||
case 5: h ^= u64(data2[4]) << 32;
|
||||
case 4: h ^= u64(data2[3]) << 24;
|
||||
case 3: h ^= u64(data2[2]) << 16;
|
||||
case 2: h ^= u64(data2[1]) << 8;
|
||||
case 1: h ^= u64(data2[0]);
|
||||
h *= m;
|
||||
};
|
||||
|
||||
h ^= h >> r;
|
||||
h *= m;
|
||||
h ^= h >> r;
|
||||
|
||||
return h;
|
||||
}
|
||||
#else
|
||||
// CRC32 hash using the SSE4.2 instruction
|
||||
u64 GetCRC32(const u8 *src, int len, u32 samples)
|
||||
{
|
||||
#if _M_SSE >= 0x402
|
||||
u32 h = len;
|
||||
u32 Step = (len/4);
|
||||
const u32 *data = (const u32 *)src;
|
||||
const u32 *end = data + Step;
|
||||
if(samples == 0) samples = std::max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
while(data < end)
|
||||
{
|
||||
h = _mm_crc32_u32(h, data[0]);
|
||||
data += Step;
|
||||
}
|
||||
|
||||
const u8 *data2 = (const u8*)end;
|
||||
return (u64)_mm_crc32_u32(h, u32(data2[0]));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
|
||||
inline u32 getblock(const u32 * p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//----------
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
|
||||
// avalanches all bits to within 0.25% bias
|
||||
|
||||
inline u32 fmix32(u32 h)
|
||||
{
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2)
|
||||
{
|
||||
k1 *= c1;
|
||||
k1 = __rotl(k1,11);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
h1 += h2;
|
||||
|
||||
h2 = __rotl(h2,17);
|
||||
|
||||
k2 *= c2;
|
||||
k2 = __rotl(k2,11);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = h1*3+0x52dce729;
|
||||
h2 = h2*3+0x38495ab5;
|
||||
|
||||
c1 = c1*5+0x7b7d159c;
|
||||
c2 = c2*5+0x6bce6396;
|
||||
}
|
||||
|
||||
//----------
|
||||
|
||||
u64 GetMurmurHash3(const u8* src, int len, u32 samples)
|
||||
{
|
||||
const u8 * data = (const u8*)src;
|
||||
u32 out[2];
|
||||
const int nblocks = len / 8;
|
||||
u32 Step = (len / 4);
|
||||
if(samples == 0) samples = std::max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
|
||||
u32 h1 = 0x8de1c3ac;
|
||||
u32 h2 = 0xbab98226;
|
||||
|
||||
u32 c1 = 0x95543787;
|
||||
u32 c2 = 0x2ad7eb25;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const u32 * blocks = (const u32 *)(data + nblocks*8);
|
||||
|
||||
for(int i = -nblocks; i < 0; i+=Step)
|
||||
{
|
||||
u32 k1 = getblock(blocks,i*2+0);
|
||||
u32 k2 = getblock(blocks,i*2+1);
|
||||
|
||||
bmix32(h1,h2,k1,k2,c1,c2);
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const u8 * tail = (const u8*)(data + nblocks*8);
|
||||
|
||||
u32 k1 = 0;
|
||||
u32 k2 = 0;
|
||||
|
||||
switch(len & 7)
|
||||
{
|
||||
case 7: k2 ^= tail[6] << 16;
|
||||
case 6: k2 ^= tail[5] << 8;
|
||||
case 5: k2 ^= tail[4] << 0;
|
||||
case 4: k1 ^= tail[3] << 24;
|
||||
case 3: k1 ^= tail[2] << 16;
|
||||
case 2: k1 ^= tail[1] << 8;
|
||||
case 1: k1 ^= tail[0] << 0;
|
||||
bmix32(h1,h2,k1,k2,c1,c2);
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix32(h1);
|
||||
h2 = fmix32(h2);
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
out[0] = h1;
|
||||
out[1] = h2;
|
||||
|
||||
return *((u64 *)&out);
|
||||
}
|
||||
|
||||
/* FIXME: The old 32-bit version of this hash made different hashes than the
|
||||
64-bit version. Until someone can make a new version of the 32-bit one that
|
||||
makes identical hashes, this is just a c/p of the 64-bit one. */
|
||||
u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
|
||||
{
|
||||
const u64 m = 0xc6a4a7935bd1e995ULL;
|
||||
u64 h = len * m;
|
||||
const int r = 47;
|
||||
u32 Step = (len / 8);
|
||||
const u64 *data = (const u64 *)src;
|
||||
const u64 *end = data + Step;
|
||||
if(samples == 0) samples = std::max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
while(data < end)
|
||||
{
|
||||
u64 k = data[0];
|
||||
data+=Step;
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
h ^= k;
|
||||
h *= m;
|
||||
}
|
||||
|
||||
const u8 * data2 = (const u8*)end;
|
||||
|
||||
switch(len & 7)
|
||||
{
|
||||
case 7: h ^= u64(data2[6]) << 48;
|
||||
case 6: h ^= u64(data2[5]) << 40;
|
||||
case 5: h ^= u64(data2[4]) << 32;
|
||||
case 4: h ^= u64(data2[3]) << 24;
|
||||
case 3: h ^= u64(data2[2]) << 16;
|
||||
case 2: h ^= u64(data2[1]) << 8;
|
||||
case 1: h ^= u64(data2[0]);
|
||||
h *= m;
|
||||
};
|
||||
|
||||
h ^= h >> r;
|
||||
h *= m;
|
||||
h ^= h >> r;
|
||||
|
||||
return h;
|
||||
}
|
||||
#endif
|
||||
|
||||
u64 GetHash64(const u8 *src, int len, u32 samples)
|
||||
{
|
||||
return ptrHashFunction(src, len, samples);
|
||||
}
|
||||
|
||||
// sets the hash function used for the texture cache
|
||||
void SetHash64Function(bool useHiresTextures)
|
||||
{
|
||||
if (useHiresTextures)
|
||||
{
|
||||
ptrHashFunction = &GetHashHiresTexture;
|
||||
}
|
||||
#if _M_SSE >= 0x402
|
||||
else if (cpu_info.bSSE4_2 && !useHiresTextures) // sse crc32 version
|
||||
{
|
||||
ptrHashFunction = &GetCRC32;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
ptrHashFunction = &GetMurmurHash3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _HASH_H_
|
||||
#define _HASH_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
u32 HashFletcher(const u8* data_u8, size_t length); // FAST. Length & 1 == 0.
|
||||
u32 HashAdler32(const u8* data, size_t len); // Fairly accurate, slightly slower
|
||||
u32 HashFNV(const u8* ptr, int length); // Another fast and decent hash
|
||||
u32 HashEctor(const u8* ptr, int length); // JUNK. DO NOT USE FOR NEW THINGS
|
||||
u64 GetCRC32(const u8 *src, int len, u32 samples); // SSE4.2 version of CRC32
|
||||
u64 GetHashHiresTexture(const u8 *src, int len, u32 samples);
|
||||
u64 GetMurmurHash3(const u8 *src, int len, u32 samples);
|
||||
u64 GetHash64(const u8 *src, int len, u32 samples);
|
||||
void SetHash64Function(bool useHiresTextures);
|
||||
#endif // _HASH_H_
|
|
@ -0,0 +1,335 @@
|
|||
// Copyright (c) 2013- PPSSPP 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 or later versions.
|
||||
|
||||
// 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 git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "input/input_state.h"
|
||||
#include "Core/Config.h"
|
||||
#include "KeyMap.h"
|
||||
|
||||
using namespace KeyMap;
|
||||
|
||||
// Platform specific
|
||||
// default
|
||||
std::map<int,int> *platform_keymap = NULL;
|
||||
|
||||
// Default key mapping
|
||||
// Ugly, yet the cleanest way
|
||||
// I could find to create a
|
||||
// static map.
|
||||
// Still nicer than what
|
||||
// I once did in C.
|
||||
struct DefaultKeyMap {
|
||||
static std::map<int,int> init()
|
||||
{
|
||||
std::map<int,int> m;
|
||||
m[KEY_x] = PAD_BUTTON_A;
|
||||
m[KEY_z] = PAD_BUTTON_B;
|
||||
m[KEY_s] = PAD_BUTTON_X;
|
||||
m[KEY_a] = PAD_BUTTON_Y;
|
||||
m[KEY_q] = PAD_BUTTON_LBUMPER;
|
||||
m[KEY_w] = PAD_BUTTON_RBUMPER;
|
||||
m[KEY_SPACE] = PAD_BUTTON_START;
|
||||
m[KEY_ENTER] = PAD_BUTTON_SELECT;
|
||||
m[KEY_ARROW_UP] = PAD_BUTTON_UP;
|
||||
m[KEY_ARROW_DOWN] = PAD_BUTTON_DOWN;
|
||||
m[KEY_ARROW_LEFT] = PAD_BUTTON_LEFT;
|
||||
m[KEY_ARROW_RIGHT] = PAD_BUTTON_RIGHT;
|
||||
m[KEY_TAB] = PAD_BUTTON_MENU;
|
||||
m[KEY_BACKSPACE] = PAD_BUTTON_BACK;
|
||||
m[KEY_ANALOG_UP] = PAD_BUTTON_JOY_UP;
|
||||
m[KEY_ANALOG_DOWN] = PAD_BUTTON_JOY_DOWN;
|
||||
m[KEY_ANALOG_LEFT] = PAD_BUTTON_JOY_LEFT;
|
||||
m[KEY_ANALOG_RIGHT] = PAD_BUTTON_JOY_RIGHT;
|
||||
m[KEY_CTRL_LEFT] = PAD_BUTTON_LEFT_THUMB;
|
||||
m[KEY_ALT_LEFT] = PAD_BUTTON_RIGHT_THUMB;
|
||||
return m;
|
||||
}
|
||||
static std::map<int,int> KeyMap;
|
||||
};
|
||||
|
||||
std::map<int,int> DefaultKeyMap::KeyMap = DefaultKeyMap::init();
|
||||
|
||||
// Key & Button names
|
||||
struct KeyMap_IntStrPair {
|
||||
int key;
|
||||
std::string name;
|
||||
};
|
||||
const KeyMap_IntStrPair key_names[] = {
|
||||
{KEY_a, "a"},
|
||||
{KEY_b, "b"},
|
||||
{KEY_c, "c"},
|
||||
{KEY_d, "d"},
|
||||
{KEY_e, "e"},
|
||||
{KEY_f, "f"},
|
||||
{KEY_g, "g"},
|
||||
{KEY_h, "h"},
|
||||
{KEY_i, "i"},
|
||||
{KEY_j, "j"},
|
||||
{KEY_k, "k"},
|
||||
{KEY_l, "l"},
|
||||
{KEY_m, "m"},
|
||||
{KEY_n, "n"},
|
||||
{KEY_o, "o"},
|
||||
{KEY_p, "p"},
|
||||
{KEY_q, "q"},
|
||||
{KEY_r, "r"},
|
||||
{KEY_s, "s"},
|
||||
{KEY_t, "t"},
|
||||
{KEY_u, "u"},
|
||||
{KEY_v, "v"},
|
||||
{KEY_w, "w"},
|
||||
{KEY_x, "x"},
|
||||
{KEY_y, "y"},
|
||||
{KEY_z, "z"},
|
||||
|
||||
{KEY_A, "A"},
|
||||
{KEY_B, "B"},
|
||||
{KEY_C, "C"},
|
||||
{KEY_D, "D"},
|
||||
{KEY_E, "E"},
|
||||
{KEY_F, "F"},
|
||||
{KEY_G, "G"},
|
||||
{KEY_H, "H"},
|
||||
{KEY_I, "I"},
|
||||
{KEY_J, "J"},
|
||||
{KEY_K, "K"},
|
||||
{KEY_L, "L"},
|
||||
{KEY_M, "M"},
|
||||
{KEY_N, "N"},
|
||||
{KEY_O, "O"},
|
||||
{KEY_P, "P"},
|
||||
{KEY_Q, "Q"},
|
||||
{KEY_R, "R"},
|
||||
{KEY_S, "S"},
|
||||
{KEY_T, "T"},
|
||||
{KEY_U, "U"},
|
||||
{KEY_V, "V"},
|
||||
{KEY_W, "W"},
|
||||
{KEY_X, "X"},
|
||||
{KEY_Y, "Y"},
|
||||
{KEY_Z, "Z"},
|
||||
|
||||
{KEY_1, "1"},
|
||||
{KEY_2, "2"},
|
||||
{KEY_3, "3"},
|
||||
{KEY_4, "4"},
|
||||
{KEY_5, "5"},
|
||||
{KEY_6, "6"},
|
||||
{KEY_7, "7"},
|
||||
{KEY_8, "8"},
|
||||
{KEY_9, "9"},
|
||||
{KEY_0, "0"},
|
||||
|
||||
|
||||
{KEY_BACKSPACE, "Backspace"},
|
||||
{KEY_TAB, "Tab"},
|
||||
{KEY_ENTER, "Enter"},
|
||||
{KEY_SHIFT_LEFT, "Shift"},
|
||||
{KEY_SHIFT_RIGHT, "Shift"},
|
||||
{KEY_CTRL_LEFT, "Ctrl"},
|
||||
{KEY_CTRL_RIGHT, "Ctrl"},
|
||||
{KEY_ALT_LEFT, "Alt"},
|
||||
{KEY_ALT_RIGHT, "Alt"},
|
||||
{KEY_SPACE, "Space"},
|
||||
{KEY_SUPER, "Super"},
|
||||
{KEY_SPACE, "Space"},
|
||||
|
||||
{KEY_VOLUME_UP, "Vol Up"},
|
||||
{KEY_VOLUME_DOWN, "Vol Down"},
|
||||
{KEY_HOME, "Home"},
|
||||
{KEY_CALL_START, "Start Call"},
|
||||
{KEY_CALL_END, "End Call"},
|
||||
|
||||
{KEY_FASTFORWARD, "Fast foward"},
|
||||
|
||||
{KEY_ARROW_LEFT, "Left"},
|
||||
{KEY_ARROW_UP, "Up"},
|
||||
{KEY_ARROW_RIGHT, "Right"},
|
||||
{KEY_ARROW_DOWN, "Down"},
|
||||
|
||||
{KEY_ANALOG_LEFT, "Analog Left"},
|
||||
{KEY_ANALOG_UP, "Analog Up"},
|
||||
{KEY_ANALOG_RIGHT, "Analog Right"},
|
||||
{KEY_ANALOG_DOWN, "Analog Down"},
|
||||
|
||||
{KEY_ANALOG_ALT_LEFT, "Alt analog Left"},
|
||||
{KEY_ANALOG_ALT_UP, "Alt analog Up"},
|
||||
{KEY_ANALOG_ALT_RIGHT, "Alt analog Right"},
|
||||
{KEY_ANALOG_ALT_DOWN, "Alt analog Down"},
|
||||
|
||||
{KEY_EXTRA1, "Extra1"},
|
||||
{KEY_EXTRA2, "Extra2"},
|
||||
{KEY_EXTRA3, "Extra3"},
|
||||
{KEY_EXTRA4, "Extra4"},
|
||||
{KEY_EXTRA5, "Extra5"},
|
||||
{KEY_EXTRA6, "Extra6"},
|
||||
{KEY_EXTRA7, "Extra7"},
|
||||
{KEY_EXTRA8, "Extra8"},
|
||||
{KEY_EXTRA9, "Extra9"},
|
||||
{KEY_EXTRA0, "Extra0"},
|
||||
};
|
||||
static int key_names_count = sizeof(key_names) / sizeof(key_names[0]);
|
||||
static std::string unknown_key_name = "Unknown";
|
||||
const KeyMap_IntStrPair psp_button_names[] = {
|
||||
{PAD_BUTTON_A, "○"},
|
||||
{PAD_BUTTON_B, "⨯"},
|
||||
{PAD_BUTTON_X, "□"},
|
||||
{PAD_BUTTON_Y, "△"},
|
||||
{PAD_BUTTON_LBUMPER, "L"},
|
||||
{PAD_BUTTON_RBUMPER, "R"},
|
||||
{PAD_BUTTON_START, "Start"},
|
||||
{PAD_BUTTON_SELECT, "Select"},
|
||||
{PAD_BUTTON_UP, "Up"},
|
||||
{PAD_BUTTON_DOWN, "Down"},
|
||||
{PAD_BUTTON_LEFT, "Left"},
|
||||
{PAD_BUTTON_RIGHT, "Right"},
|
||||
|
||||
{PAD_BUTTON_MENU, "Menu"},
|
||||
{PAD_BUTTON_BACK, "Back"},
|
||||
|
||||
{PAD_BUTTON_JOY_UP, "Analog Up"},
|
||||
{PAD_BUTTON_JOY_DOWN, "Analog Down"},
|
||||
{PAD_BUTTON_JOY_LEFT, "Analog Left"},
|
||||
{PAD_BUTTON_JOY_RIGHT, "Analog Right"},
|
||||
|
||||
{PAD_BUTTON_LEFT_THUMB, "Left analog click"},
|
||||
{PAD_BUTTON_RIGHT_THUMB, "Right analog click"},
|
||||
};
|
||||
static int psp_button_names_count = sizeof(psp_button_names) / sizeof(psp_button_names[0]);
|
||||
|
||||
|
||||
static std::string FindName(int key, const KeyMap_IntStrPair list[], int size)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
if (list[i].key == key)
|
||||
return list[i].name;
|
||||
|
||||
return unknown_key_name;
|
||||
}
|
||||
|
||||
static std::string KeyMap::GetKeyName(KeyMap::Key key)
|
||||
{
|
||||
return FindName((int)key, key_names, key_names_count);
|
||||
}
|
||||
|
||||
static std::string KeyMap::GetPspButtonName(int btn)
|
||||
{
|
||||
return FindName(btn, key_names, key_names_count);
|
||||
}
|
||||
|
||||
static bool FindKeyMapping(int key, int *map_id, int *psp_button)
|
||||
{
|
||||
std::map<int,int>::iterator it;
|
||||
if (*map_id >= 0) {
|
||||
// check user configuration
|
||||
std::map<int,int> user_map = g_Config.iMappingMap;
|
||||
it = user_map.find(key);
|
||||
if (it != user_map.end()) {
|
||||
*map_id = 0;
|
||||
*psp_button = it->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (*map_id >= 1 && platform_keymap != NULL) {
|
||||
// check optional platform specific keymap
|
||||
std::map<int,int> port_map = *platform_keymap;
|
||||
it = port_map.find(key);
|
||||
if (it != port_map.end()) {
|
||||
*map_id = 1;
|
||||
*psp_button = it->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (*map_id >= 2) {
|
||||
// check default keymap
|
||||
const std::map<int,int> default_map = DefaultKeyMap::KeyMap;
|
||||
const std::map<int,int>::const_iterator it = default_map.find(key);
|
||||
if (it != default_map.end()) {
|
||||
*map_id = 2;
|
||||
*psp_button = it->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*map_id = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int KeyMap::KeyToPspButton(const KeyMap::Key key)
|
||||
{
|
||||
int search_start_layer = 0;
|
||||
int psp_button;
|
||||
|
||||
if (FindKeyMapping((int)key, &search_start_layer, &psp_button))
|
||||
return psp_button;
|
||||
|
||||
return KEYMAP_ERROR_UNKNOWN_KEY;
|
||||
}
|
||||
|
||||
static bool KeyMap::IsMappedKey(Key key)
|
||||
{
|
||||
return KeyMap::KeyToPspButton(key) != KEYMAP_ERROR_UNKNOWN_KEY;
|
||||
}
|
||||
|
||||
|
||||
static std::string KeyMap::NamePspButtonFromKey(KeyMap::Key key)
|
||||
{
|
||||
return KeyMap::GetPspButtonName(KeyMap::KeyToPspButton(key));
|
||||
}
|
||||
|
||||
static std::string KeyMap::NameKeyFromPspButton(int btn)
|
||||
{
|
||||
// We drive our iteration
|
||||
// with the list of key names.
|
||||
for (int i = 0; i < key_names_count; i++) {
|
||||
const struct KeyMap_IntStrPair *key_name = key_names + i;
|
||||
if (btn == KeyMap::KeyToPspButton((KeyMap::Key)key_name->key))
|
||||
return key_name->name;
|
||||
}
|
||||
|
||||
// all psp buttons are mapped from some key
|
||||
// but it appears we do not have a name
|
||||
// for this key.
|
||||
return unknown_key_name;
|
||||
}
|
||||
|
||||
static int KeyMap::SetKeyMapping(KeyMap::Key key, int btn)
|
||||
{
|
||||
if (KeyMap::IsMappedKey(key))
|
||||
return KEYMAP_ERROR_KEY_ALREADY_USED;
|
||||
|
||||
g_Config.iMappingMap[key] = btn;
|
||||
return btn;
|
||||
}
|
||||
|
||||
static int KeyMap::RegisterPlatformDefaultKeyMap(std::map<int,int> *overriding_map)
|
||||
{
|
||||
if (overriding_map == NULL)
|
||||
return 1;
|
||||
platform_keymap = overriding_map;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void KeyMap::DeregisterPlatformDefaultKeyMap(void)
|
||||
{
|
||||
platform_keymap = NULL;
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
// Copyright (c) 2013- PPSSPP 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 or later versions.
|
||||
|
||||
// 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 git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#define KEYMAP_ERROR_KEY_ALREADY_USED -1
|
||||
#define KEYMAP_ERROR_UNKNOWN_KEY 0
|
||||
|
||||
// KeyMap
|
||||
// A translation layer for
|
||||
// key assignment. Provides
|
||||
// integration with Core's
|
||||
// config state.
|
||||
//
|
||||
// Does not handle input
|
||||
// state managment.
|
||||
//
|
||||
// Platform ports should
|
||||
// map their platform's
|
||||
// keys to KeyMap's keys.
|
||||
// Then have KeyMap transform
|
||||
// those into psp buttons.
|
||||
namespace KeyMap {
|
||||
enum Key {
|
||||
// Lower class latin
|
||||
KEY_q = 1, // top row
|
||||
KEY_w,
|
||||
KEY_e,
|
||||
KEY_r,
|
||||
KEY_t,
|
||||
KEY_y,
|
||||
KEY_u,
|
||||
KEY_i,
|
||||
KEY_o,
|
||||
KEY_p,
|
||||
|
||||
KEY_a, // mid row
|
||||
KEY_s,
|
||||
KEY_d,
|
||||
KEY_f,
|
||||
KEY_g,
|
||||
KEY_h,
|
||||
KEY_j,
|
||||
KEY_k,
|
||||
KEY_l,
|
||||
|
||||
KEY_z, // low row
|
||||
KEY_x,
|
||||
KEY_c,
|
||||
KEY_v,
|
||||
KEY_b,
|
||||
KEY_n,
|
||||
KEY_m,
|
||||
|
||||
// Upper class latin
|
||||
KEY_Q, // top row
|
||||
KEY_W,
|
||||
KEY_E,
|
||||
KEY_R,
|
||||
KEY_T,
|
||||
KEY_Y,
|
||||
KEY_U,
|
||||
KEY_I,
|
||||
KEY_O,
|
||||
KEY_P,
|
||||
|
||||
KEY_A, // mid row
|
||||
KEY_S,
|
||||
KEY_D,
|
||||
KEY_F,
|
||||
KEY_G,
|
||||
KEY_H,
|
||||
KEY_J,
|
||||
KEY_K,
|
||||
KEY_L,
|
||||
|
||||
KEY_Z, // low row
|
||||
KEY_X,
|
||||
KEY_C,
|
||||
KEY_V,
|
||||
KEY_B,
|
||||
KEY_N,
|
||||
KEY_M,
|
||||
|
||||
|
||||
// Numeric
|
||||
KEY_1,
|
||||
KEY_2,
|
||||
KEY_3,
|
||||
KEY_4,
|
||||
KEY_5,
|
||||
KEY_6,
|
||||
KEY_7,
|
||||
KEY_8,
|
||||
KEY_9,
|
||||
KEY_0,
|
||||
|
||||
// Special keys
|
||||
KEY_ARROW_LEFT,
|
||||
KEY_ARROW_RIGHT,
|
||||
KEY_ARROW_UP,
|
||||
KEY_ARROW_DOWN,
|
||||
|
||||
KEY_ANALOG_LEFT,
|
||||
KEY_ANALOG_RIGHT,
|
||||
KEY_ANALOG_UP,
|
||||
KEY_ANALOG_DOWN,
|
||||
|
||||
KEY_ANALOG_ALT_LEFT,
|
||||
KEY_ANALOG_ALT_RIGHT,
|
||||
KEY_ANALOG_ALT_UP,
|
||||
KEY_ANALOG_ALT_DOWN,
|
||||
|
||||
KEY_SPACE,
|
||||
KEY_ENTER,
|
||||
KEY_CTRL_LEFT,
|
||||
KEY_CTRL_RIGHT,
|
||||
KEY_SHIFT_LEFT,
|
||||
KEY_SHIFT_RIGHT,
|
||||
KEY_ALT_LEFT,
|
||||
KEY_ALT_RIGHT,
|
||||
KEY_BACKSPACE,
|
||||
KEY_SUPER,
|
||||
KEY_TAB,
|
||||
|
||||
// Mobile Keys
|
||||
KEY_VOLUME_UP,
|
||||
KEY_VOLUME_DOWN,
|
||||
KEY_HOME,
|
||||
KEY_CALL_START,
|
||||
KEY_CALL_END,
|
||||
|
||||
// Special PPSSPP keys
|
||||
KEY_FASTFORWARD,
|
||||
|
||||
// Extra keys
|
||||
// Use for platform specific keys.
|
||||
// Example: android's back btn
|
||||
KEY_EXTRA1,
|
||||
KEY_EXTRA2,
|
||||
KEY_EXTRA3,
|
||||
KEY_EXTRA4,
|
||||
KEY_EXTRA5,
|
||||
KEY_EXTRA6,
|
||||
KEY_EXTRA7,
|
||||
KEY_EXTRA8,
|
||||
KEY_EXTRA9,
|
||||
KEY_EXTRA0,
|
||||
|
||||
// TODO: Add any missing keys.
|
||||
// Many can be found in the
|
||||
// window's port's keyboard
|
||||
// files.
|
||||
};
|
||||
|
||||
// Use if you need to
|
||||
// display the textual
|
||||
// name
|
||||
// These functions are not
|
||||
// fast, do not call them
|
||||
// a million times.
|
||||
static std::string GetKeyName(Key);
|
||||
static std::string GetPspButtonName(int);
|
||||
|
||||
// Use if to translate
|
||||
// KeyMap Keys to PSP
|
||||
// buttons.
|
||||
// You should have
|
||||
// already translated
|
||||
// your platform's keys
|
||||
// to KeyMap keys.
|
||||
//
|
||||
// Returns KEYMAP_ERROR_UNKNOWN_KEY
|
||||
// for any unmapped key
|
||||
static int KeyToPspButton(Key);
|
||||
|
||||
static bool IsMappedKey(Key);
|
||||
|
||||
// Might be usful if you want
|
||||
// to provide hints to users
|
||||
// upon mapping conflicts
|
||||
static std::string NamePspButtonFromKey(Key);
|
||||
|
||||
// Use for showing the existing
|
||||
// key mapping.
|
||||
static std::string NameKeyFromPspButton(int);
|
||||
|
||||
// Configure the key mapping.
|
||||
// Any configuration will
|
||||
// be saved to the Core
|
||||
// config.
|
||||
//
|
||||
// Returns KEYMAP_ERROR_KEY_ALREADY_USED
|
||||
// for mapping conflicts. 0 otherwise.
|
||||
static int SetKeyMapping(Key, int);
|
||||
|
||||
// Platform specific keymaps
|
||||
// override KeyMap's defaults.
|
||||
// They do not override user's
|
||||
// configuration.
|
||||
// A platform default keymap
|
||||
// does not need to cover
|
||||
// all psp buttons.
|
||||
// Any buttons missing will
|
||||
// fallback to KeyMap's keymap.
|
||||
static int RegisterPlatformDefaultKeyMap(std::map<int,int> *);
|
||||
static void DeregisterPlatformDefaultKeyMap(void);
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _LINEAR_DISKCACHE
|
||||
#define _LINEAR_DISKCACHE
|
||||
|
||||
#include "Common.h"
|
||||
#include <fstream>
|
||||
|
||||
// Increment this every time you change shader generation code.
|
||||
enum
|
||||
{
|
||||
LINEAR_DISKCACHE_VER = 6979
|
||||
};
|
||||
|
||||
// On disk format:
|
||||
//header{
|
||||
// u32 'DCAC';
|
||||
// u32 version; // svn_rev
|
||||
// u16 sizeof(key_type);
|
||||
// u16 sizeof(value_type);
|
||||
//}
|
||||
|
||||
//key_value_pair{
|
||||
// u32 value_size;
|
||||
// key_type key;
|
||||
// value_type[value_size] value;
|
||||
//}
|
||||
|
||||
template <typename K, typename V>
|
||||
class LinearDiskCacheReader
|
||||
{
|
||||
public:
|
||||
virtual void Read(const K &key, const V *value, u32 value_size) = 0;
|
||||
};
|
||||
|
||||
// Dead simple unsorted key-value store with append functionality.
|
||||
// No random read functionality, all reading is done in OpenAndRead.
|
||||
// Keys and values can contain any characters, including \0.
|
||||
//
|
||||
// Suitable for caching generated shader bytecode between executions.
|
||||
// Not tuned for extreme performance but should be reasonably fast.
|
||||
// Does not support keys or values larger than 2GB, which should be reasonable.
|
||||
// Keys must have non-zero length; values can have zero length.
|
||||
|
||||
// K and V are some POD type
|
||||
// K : the key type
|
||||
// V : value array type
|
||||
template <typename K, typename V>
|
||||
class LinearDiskCache
|
||||
{
|
||||
public:
|
||||
// return number of read entries
|
||||
u32 OpenAndRead(const char *filename, LinearDiskCacheReader<K, V> &reader)
|
||||
{
|
||||
using std::ios_base;
|
||||
|
||||
// close any currently opened file
|
||||
Close();
|
||||
m_num_entries = 0;
|
||||
|
||||
// try opening for reading/writing
|
||||
m_file.open(filename, ios_base::in | ios_base::out | ios_base::binary);
|
||||
|
||||
m_file.seekg(0, std::ios::end);
|
||||
std::fstream::pos_type end_pos = m_file.tellg();
|
||||
m_file.seekg(0, std::ios::beg);
|
||||
std::fstream::pos_type start_pos = m_file.tellg();
|
||||
std::streamoff file_size = end_pos - start_pos;
|
||||
|
||||
if (m_file.is_open() && ValidateHeader())
|
||||
{
|
||||
// good header, read some key/value pairs
|
||||
K key;
|
||||
|
||||
V *value = NULL;
|
||||
u32 value_size;
|
||||
u32 entry_number;
|
||||
|
||||
std::fstream::pos_type last_pos = m_file.tellg();
|
||||
|
||||
while (Read(&value_size))
|
||||
{
|
||||
std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size;
|
||||
if (next_extent > file_size)
|
||||
break;
|
||||
|
||||
delete[] value;
|
||||
value = new V[value_size];
|
||||
|
||||
// read key/value and pass to reader
|
||||
if (Read(&key) &&
|
||||
Read(value, value_size) &&
|
||||
Read(&entry_number) &&
|
||||
entry_number == m_num_entries+1)
|
||||
{
|
||||
reader.Read(key, value, value_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
m_num_entries++;
|
||||
last_pos = m_file.tellg();
|
||||
}
|
||||
m_file.seekp(last_pos);
|
||||
m_file.clear();
|
||||
|
||||
delete[] value;
|
||||
return m_num_entries;
|
||||
}
|
||||
|
||||
// failed to open file for reading or bad header
|
||||
// close and recreate file
|
||||
Close();
|
||||
m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
|
||||
WriteHeader();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sync()
|
||||
{
|
||||
m_file.flush();
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
if (m_file.is_open())
|
||||
m_file.close();
|
||||
// clear any error flags
|
||||
m_file.clear();
|
||||
}
|
||||
|
||||
// Appends a key-value pair to the store.
|
||||
void Append(const K &key, const V *value, u32 value_size)
|
||||
{
|
||||
// TODO: Should do a check that we don't already have "key"? (I think each caller does that already.)
|
||||
Write(&value_size);
|
||||
Write(&key);
|
||||
Write(value, value_size);
|
||||
m_num_entries++;
|
||||
Write(&m_num_entries);
|
||||
}
|
||||
|
||||
private:
|
||||
void WriteHeader()
|
||||
{
|
||||
Write(&m_header);
|
||||
}
|
||||
|
||||
bool ValidateHeader()
|
||||
{
|
||||
char file_header[sizeof(Header)];
|
||||
|
||||
return (Read(file_header, sizeof(Header))
|
||||
&& !memcmp((const char*)&m_header, file_header, sizeof(Header)));
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
bool Write(const D *data, u32 count = 1)
|
||||
{
|
||||
return m_file.write((const char*)data, count * sizeof(D)).good();
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
bool Read(const D *data, u32 count = 1)
|
||||
{
|
||||
return m_file.read((char*)data, count * sizeof(D)).good();
|
||||
}
|
||||
|
||||
struct Header
|
||||
{
|
||||
Header()
|
||||
: id(*(u32*)"DCAC")
|
||||
, ver(LINEAR_DISKCACHE_VER)
|
||||
, key_t_size(sizeof(K))
|
||||
, value_t_size(sizeof(V))
|
||||
{}
|
||||
|
||||
const u32 id, ver;
|
||||
const u16 key_t_size, value_t_size;
|
||||
|
||||
} m_header;
|
||||
|
||||
std::fstream m_file;
|
||||
u32 m_num_entries;
|
||||
};
|
||||
|
||||
#endif // _LINEAR_DISKCACHE
|
|
@ -0,0 +1,150 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __arm__
|
||||
#if !defined(ARM)
|
||||
#define ARM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and debugprintfs from the game itself.
|
||||
#define ERROR_LEVEL 2 // Important errors.
|
||||
#define WARNING_LEVEL 3 // Something is suspicious.
|
||||
#define INFO_LEVEL 4 // General information.
|
||||
#define DEBUG_LEVEL 5 // Detailed debugging - might make things slow.
|
||||
#define VERBOSE_LEVEL 6 // Noisy debugging - sometimes needed but usually unimportant.
|
||||
|
||||
#if !defined(_WIN32) && !defined(PANDORA)
|
||||
#if defined(MAEMO)
|
||||
//ucontext.h will be then skipped
|
||||
#define _SYS_UCONTEXT_H 1
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
namespace LogTypes
|
||||
{
|
||||
|
||||
enum LOG_TYPE {
|
||||
MASTER_LOG,
|
||||
BOOT,
|
||||
COMMON,
|
||||
CPU,
|
||||
LOADER,
|
||||
IO,
|
||||
PAD,
|
||||
FILESYS,
|
||||
DISCIO,
|
||||
G3D,
|
||||
DMA,
|
||||
INTC,
|
||||
MEMMAP,
|
||||
SOUND,
|
||||
SAS,
|
||||
HLE,
|
||||
TIMER,
|
||||
VIDEO,
|
||||
DYNA_REC,
|
||||
NETPLAY,
|
||||
ME,
|
||||
|
||||
NUMBER_OF_LOGS, // Must be last
|
||||
JIT = DYNA_REC,
|
||||
};
|
||||
|
||||
// FIXME: should this be removed?
|
||||
enum LOG_LEVELS {
|
||||
LNOTICE = NOTICE_LEVEL,
|
||||
LERROR = ERROR_LEVEL,
|
||||
LWARNING = WARNING_LEVEL,
|
||||
LINFO = INFO_LEVEL,
|
||||
LDEBUG = DEBUG_LEVEL,
|
||||
LVERBOSE = VERBOSE_LEVEL,
|
||||
};
|
||||
|
||||
#define LOGTYPES_LEVELS LogTypes::LOG_LEVELS
|
||||
#define LOGTYPES_TYPE LogTypes::LOG_TYPE
|
||||
|
||||
} // namespace
|
||||
|
||||
void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type,
|
||||
const char *file, int line, const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
#endif
|
||||
;
|
||||
|
||||
#if defined(LOGGING) || defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#define MAX_LOGLEVEL DEBUG_LEVEL
|
||||
#else
|
||||
#ifndef MAX_LOGLEVEL
|
||||
#define MAX_LOGLEVEL INFO_LEVEL
|
||||
#endif // loglevel
|
||||
#endif // logging
|
||||
|
||||
// Let the compiler optimize this out
|
||||
#define GENERIC_LOG(t, v, ...) { \
|
||||
if (v <= MAX_LOGLEVEL) \
|
||||
GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define ERROR_LOG(t,...) { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) }
|
||||
#define WARN_LOG(t,...) { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) }
|
||||
#define NOTICE_LOG(t,...) { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) }
|
||||
#define INFO_LOG(t,...) { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) }
|
||||
#define DEBUG_LOG(t,...) { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) }
|
||||
#define VERBOSE_LOG(t,...) { GENERIC_LOG(LogTypes::t, LogTypes::LVERBOSE, __VA_ARGS__) }
|
||||
|
||||
#if MAX_LOGLEVEL >= DEBUG_LEVEL
|
||||
#define _dbg_assert_(_t_, _a_) \
|
||||
if (!(_a_)) {\
|
||||
ERROR_LOG(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \
|
||||
__LINE__, __FILE__, __TIME__); \
|
||||
if (!PanicYesNo("*** Assertion (see log)***\n")) {Crash();} \
|
||||
}
|
||||
#define _dbg_assert_msg_(_t_, _a_, ...)\
|
||||
if (!(_a_)) {\
|
||||
printf(__VA_ARGS__); \
|
||||
ERROR_LOG(_t_, __VA_ARGS__); \
|
||||
if (!PanicYesNo(__VA_ARGS__)) {Crash();} \
|
||||
}
|
||||
#define _dbg_update_() ; //Host_UpdateLogDisplay();
|
||||
|
||||
#else // not debug
|
||||
#define _dbg_update_() ;
|
||||
|
||||
#ifndef _dbg_assert_
|
||||
#define _dbg_assert_(_t_, _a_) {}
|
||||
#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {}
|
||||
#endif // dbg_assert
|
||||
#endif // MAX_LOGLEVEL DEBUG
|
||||
|
||||
#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _assert_msg_(_t_, _a_, _fmt_, ...) \
|
||||
if (!(_a_)) {\
|
||||
if (!PanicYesNo(_fmt_, __VA_ARGS__)) {Crash();} \
|
||||
}
|
||||
#else // not win32
|
||||
#define _assert_msg_(_t_, _a_, _fmt_, ...) \
|
||||
if (!(_a_)) {\
|
||||
if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \
|
||||
}
|
||||
#endif // WIN32
|
|
@ -0,0 +1,282 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 <algorithm>
|
||||
|
||||
#include "LogManager.h"
|
||||
#include "ConsoleListener.h"
|
||||
#include "Timer.h"
|
||||
#include "Thread.h"
|
||||
#include "FileUtil.h"
|
||||
#ifdef __SYMBIAN32__
|
||||
#include <e32debug.h>
|
||||
#endif
|
||||
|
||||
// Don't need to savestate this.
|
||||
const char *hleCurrentThreadName = NULL;
|
||||
|
||||
// Unfortunately this is quite slow.
|
||||
#define LOG_MSC_OUTPUTDEBUG false
|
||||
// #define LOG_MSC_OUTPUTDEBUG true
|
||||
|
||||
void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
|
||||
const char *file, int line, const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if (LogManager::GetInstance())
|
||||
LogManager::GetInstance()->Log(level, type,
|
||||
file, line, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
LogManager *LogManager::m_logManager = NULL;
|
||||
|
||||
LogManager::LogManager()
|
||||
{
|
||||
// create log files
|
||||
m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log");
|
||||
m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot");
|
||||
m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common");
|
||||
m_Log[LogTypes::CPU] = new LogContainer("CPU", "CPU");
|
||||
m_Log[LogTypes::LOADER] = new LogContainer("LOAD", "Loader");
|
||||
m_Log[LogTypes::IO] = new LogContainer("IO", "IO");
|
||||
m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "DiscIO");
|
||||
m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad");
|
||||
m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System");
|
||||
m_Log[LogTypes::G3D] = new LogContainer("G3D", "3D Graphics");
|
||||
m_Log[LogTypes::DMA] = new LogContainer("DMA", "DMA");
|
||||
m_Log[LogTypes::INTC] = new LogContainer("INTC", "Interrupts");
|
||||
m_Log[LogTypes::MEMMAP] = new LogContainer("MM", "Memory Map");
|
||||
m_Log[LogTypes::SOUND] = new LogContainer("SND", "Sound");
|
||||
m_Log[LogTypes::SAS] = new LogContainer("SAS", "Sound Mixer (Sas)");
|
||||
m_Log[LogTypes::HLE] = new LogContainer("HLE", "HLE");
|
||||
m_Log[LogTypes::TIMER] = new LogContainer("TMR", "Timer");
|
||||
m_Log[LogTypes::VIDEO] = new LogContainer("VID", "Video");
|
||||
m_Log[LogTypes::DYNA_REC] = new LogContainer("Jit", "JIT compiler");
|
||||
m_Log[LogTypes::NETPLAY] = new LogContainer("NET", "Net play");
|
||||
m_Log[LogTypes::ME] = new LogContainer("ME", "Media Engine");
|
||||
|
||||
// Remove file logging on small devices
|
||||
#if !defined(USING_GLES2) || defined(_DEBUG)
|
||||
m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str());
|
||||
m_consoleLog = new ConsoleListener();
|
||||
m_debuggerLog = new DebuggerLogListener();
|
||||
#else
|
||||
m_fileLog = NULL;
|
||||
m_consoleLog = NULL;
|
||||
m_debuggerLog = NULL;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
{
|
||||
m_Log[i]->SetEnable(true);
|
||||
#if !defined(USING_GLES2) || defined(_DEBUG)
|
||||
m_Log[i]->AddListener(m_fileLog);
|
||||
m_Log[i]->AddListener(m_consoleLog);
|
||||
#ifdef _MSC_VER
|
||||
if (IsDebuggerPresent() && m_debuggerLog != NULL && LOG_MSC_OUTPUTDEBUG)
|
||||
m_Log[i]->AddListener(m_debuggerLog);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
LogManager::~LogManager()
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
{
|
||||
#if !defined(USING_GLES2) || defined(_DEBUG)
|
||||
if (m_fileLog != NULL)
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog);
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog);
|
||||
#ifdef _MSC_VER
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
delete m_Log[i];
|
||||
if (m_fileLog != NULL)
|
||||
delete m_fileLog;
|
||||
#if !defined(USING_GLES2) || defined(_DEBUG)
|
||||
delete m_consoleLog;
|
||||
delete m_debuggerLog;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogManager::ChangeFileLog(const char *filename)
|
||||
{
|
||||
if (m_fileLog != NULL)
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog);
|
||||
delete m_fileLog;
|
||||
}
|
||||
|
||||
if (filename != NULL)
|
||||
{
|
||||
m_fileLog = new FileLogListener(filename);
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
m_Log[i]->AddListener(m_fileLog);
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::SaveConfig(IniFile::Section *section)
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
|
||||
{
|
||||
section->Set((std::string(m_Log[i]->GetShortName()) + "Enabled").c_str(), m_Log[i]->IsEnabled());
|
||||
section->Set((std::string(m_Log[i]->GetShortName()) + "Level").c_str(), (int)m_Log[i]->GetLevel());
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::LoadConfig(IniFile::Section *section)
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
|
||||
{
|
||||
bool enabled;
|
||||
int level;
|
||||
section->Get((std::string(m_Log[i]->GetShortName()) + "Enabled").c_str(), &enabled, true);
|
||||
section->Get((std::string(m_Log[i]->GetShortName()) + "Level").c_str(), &level, 0);
|
||||
m_Log[i]->SetEnable(enabled);
|
||||
m_Log[i]->SetLevel((LogTypes::LOG_LEVELS)level);
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char *file, int line, const char *format, va_list args)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_log_lock);
|
||||
|
||||
char msg[MAX_MSGLEN * 2];
|
||||
LogContainer *log = m_Log[type];
|
||||
if (!log || !log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
|
||||
return;
|
||||
|
||||
static const char level_to_char[8] = "-NEWIDV";
|
||||
char formattedTime[13];
|
||||
Common::Timer::GetTimeFormatted(formattedTime);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef _WIN32
|
||||
static const char sep = '\\';
|
||||
#else
|
||||
static const char sep = '/';
|
||||
#endif
|
||||
const char *fileshort = strrchr(file, sep);
|
||||
if (fileshort != NULL) {
|
||||
do
|
||||
--fileshort;
|
||||
while (fileshort > file && *fileshort != sep);
|
||||
if (fileshort != file)
|
||||
file = fileshort + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *msgPos = msg;
|
||||
if (hleCurrentThreadName != NULL)
|
||||
{
|
||||
msgPos += sprintf(msgPos, "%s %-12.12s %c[%s]: %s:%d ",
|
||||
formattedTime,
|
||||
hleCurrentThreadName, level_to_char[(int)level],
|
||||
log->GetShortName(),
|
||||
file, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
msgPos += sprintf(msgPos, "%s %s:%d %c[%s]: ",
|
||||
formattedTime,
|
||||
file, line, level_to_char[(int)level],
|
||||
log->GetShortName());
|
||||
}
|
||||
|
||||
msgPos += vsnprintf(msgPos, MAX_MSGLEN, format, args);
|
||||
// This will include the null terminator.
|
||||
memcpy(msgPos, "\n", sizeof("\n"));
|
||||
|
||||
log->Trigger(level, msg);
|
||||
}
|
||||
|
||||
void LogManager::Init()
|
||||
{
|
||||
m_logManager = new LogManager();
|
||||
}
|
||||
|
||||
void LogManager::Shutdown()
|
||||
{
|
||||
delete m_logManager;
|
||||
m_logManager = NULL;
|
||||
}
|
||||
|
||||
LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable)
|
||||
: m_enable(enable)
|
||||
{
|
||||
strncpy(m_fullName, fullName, 128);
|
||||
strncpy(m_shortName, shortName, 32);
|
||||
m_level = LogTypes::LDEBUG;
|
||||
}
|
||||
|
||||
// LogContainer
|
||||
void LogContainer::AddListener(LogListener *listener)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_listeners_lock);
|
||||
m_listeners.insert(listener);
|
||||
}
|
||||
|
||||
void LogContainer::RemoveListener(LogListener *listener)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_listeners_lock);
|
||||
m_listeners.erase(listener);
|
||||
}
|
||||
|
||||
void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg)
|
||||
{
|
||||
#ifdef __SYMBIAN32__
|
||||
RDebug::Printf("%s",msg);
|
||||
#else
|
||||
std::lock_guard<std::mutex> lk(m_listeners_lock);
|
||||
|
||||
std::set<LogListener*>::const_iterator i;
|
||||
for (i = m_listeners.begin(); i != m_listeners.end(); ++i)
|
||||
{
|
||||
(*i)->Log(level, msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
FileLogListener::FileLogListener(const char *filename)
|
||||
{
|
||||
m_logfile.open(filename, std::ios::app);
|
||||
SetEnable(true);
|
||||
}
|
||||
|
||||
void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
|
||||
{
|
||||
if (!IsEnabled() || !IsValid())
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lk(m_log_lock);
|
||||
m_logfile << msg << std::flush;
|
||||
}
|
||||
|
||||
void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
|
||||
{
|
||||
#if _MSC_VER
|
||||
::OutputDebugStringA(msg);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Log.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Thread.h"
|
||||
#include "FileUtil.h"
|
||||
#include "file/ini_file.h"
|
||||
|
||||
#include <set>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_MESSAGES 8000
|
||||
#define MAX_MSGLEN 1024
|
||||
|
||||
extern const char *hleCurrentThreadName;
|
||||
|
||||
// pure virtual interface
|
||||
class LogListener
|
||||
{
|
||||
public:
|
||||
virtual ~LogListener() {}
|
||||
|
||||
virtual void Log(LogTypes::LOG_LEVELS, const char *msg) = 0;
|
||||
};
|
||||
|
||||
class FileLogListener : public LogListener
|
||||
{
|
||||
public:
|
||||
FileLogListener(const char *filename);
|
||||
|
||||
void Log(LogTypes::LOG_LEVELS, const char *msg);
|
||||
|
||||
bool IsValid() { if (!m_logfile) return false; else return true; }
|
||||
bool IsEnabled() const { return m_enable; }
|
||||
void SetEnable(bool enable) { m_enable = enable; }
|
||||
|
||||
const char* GetName() const { return "file"; }
|
||||
|
||||
private:
|
||||
std::mutex m_log_lock;
|
||||
std::ofstream m_logfile;
|
||||
bool m_enable;
|
||||
};
|
||||
|
||||
class DebuggerLogListener : public LogListener
|
||||
{
|
||||
public:
|
||||
void Log(LogTypes::LOG_LEVELS, const char *msg);
|
||||
};
|
||||
|
||||
class LogContainer
|
||||
{
|
||||
public:
|
||||
LogContainer(const char* shortName, const char* fullName, bool enable = false);
|
||||
|
||||
const char* GetShortName() const { return m_shortName; }
|
||||
const char* GetFullName() const { return m_fullName; }
|
||||
|
||||
void AddListener(LogListener* listener);
|
||||
void RemoveListener(LogListener* listener);
|
||||
|
||||
void Trigger(LogTypes::LOG_LEVELS, const char *msg);
|
||||
|
||||
bool IsEnabled() const { return m_enable; }
|
||||
void SetEnable(bool enable) { m_enable = enable; }
|
||||
|
||||
LogTypes::LOG_LEVELS GetLevel() const { return m_level; }
|
||||
|
||||
void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; }
|
||||
|
||||
bool HasListeners() const { return !m_listeners.empty(); }
|
||||
|
||||
private:
|
||||
char m_fullName[128];
|
||||
char m_shortName[32];
|
||||
bool m_enable;
|
||||
LogTypes::LOG_LEVELS m_level;
|
||||
std::mutex m_listeners_lock;
|
||||
std::set<LogListener*> m_listeners;
|
||||
};
|
||||
|
||||
class ConsoleListener;
|
||||
|
||||
class LogManager : NonCopyable
|
||||
{
|
||||
private:
|
||||
LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS];
|
||||
FileLogListener *m_fileLog;
|
||||
ConsoleListener *m_consoleLog;
|
||||
DebuggerLogListener *m_debuggerLog;
|
||||
static LogManager *m_logManager; // Singleton. Ugh.
|
||||
std::mutex m_log_lock;
|
||||
|
||||
LogManager();
|
||||
~LogManager();
|
||||
public:
|
||||
|
||||
static u32 GetMaxLevel() { return MAX_LOGLEVEL; }
|
||||
|
||||
void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
|
||||
const char *file, int line, const char *fmt, va_list args);
|
||||
|
||||
void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level)
|
||||
{
|
||||
m_Log[type]->SetLevel(level);
|
||||
}
|
||||
|
||||
LogTypes::LOG_LEVELS GetLogLevel(LogTypes::LOG_TYPE type)
|
||||
{
|
||||
return m_Log[type]->GetLevel();
|
||||
}
|
||||
|
||||
void SetEnable(LogTypes::LOG_TYPE type, bool enable)
|
||||
{
|
||||
m_Log[type]->SetEnable(enable);
|
||||
}
|
||||
|
||||
bool IsEnabled(LogTypes::LOG_TYPE type) const
|
||||
{
|
||||
return m_Log[type]->IsEnabled();
|
||||
}
|
||||
|
||||
const char* GetShortName(LogTypes::LOG_TYPE type) const
|
||||
{
|
||||
return m_Log[type]->GetShortName();
|
||||
}
|
||||
|
||||
const char* GetFullName(LogTypes::LOG_TYPE type) const
|
||||
{
|
||||
return m_Log[type]->GetFullName();
|
||||
}
|
||||
|
||||
void AddListener(LogTypes::LOG_TYPE type, LogListener *listener)
|
||||
{
|
||||
m_Log[type]->AddListener(listener);
|
||||
}
|
||||
|
||||
void RemoveListener(LogTypes::LOG_TYPE type, LogListener *listener)
|
||||
{
|
||||
m_Log[type]->RemoveListener(listener);
|
||||
}
|
||||
|
||||
FileLogListener *GetFileListener() const
|
||||
{
|
||||
return m_fileLog;
|
||||
}
|
||||
|
||||
ConsoleListener *GetConsoleListener() const
|
||||
{
|
||||
return m_consoleLog;
|
||||
}
|
||||
|
||||
DebuggerLogListener *GetDebuggerListener() const
|
||||
{
|
||||
return m_debuggerLog;
|
||||
}
|
||||
|
||||
static LogManager* GetInstance()
|
||||
{
|
||||
return m_logManager;
|
||||
}
|
||||
|
||||
static void SetInstance(LogManager *logManager)
|
||||
{
|
||||
m_logManager = logManager;
|
||||
}
|
||||
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
void ChangeFileLog(const char *filename);
|
||||
|
||||
void SaveConfig(IniFile::Section *section);
|
||||
void LoadConfig(IniFile::Section *section);
|
||||
};
|
|
@ -0,0 +1,280 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "MathUtil.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
|
||||
namespace {
|
||||
#ifdef USE_SSE
|
||||
static u32 saved_sse_state = _mm_getcsr();
|
||||
static const u32 default_sse_state = _mm_getcsr();
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace MathUtil
|
||||
{
|
||||
|
||||
u32 ClassifyDouble(double dvalue)
|
||||
{
|
||||
// TODO: Optimize the below to be as fast as possible.
|
||||
IntDouble value;
|
||||
value.d = dvalue;
|
||||
u64 sign = value.i & DOUBLE_SIGN;
|
||||
u64 exp = value.i & DOUBLE_EXP;
|
||||
if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP)
|
||||
{
|
||||
// Nice normalized number.
|
||||
return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 mantissa = value.i & DOUBLE_FRAC;
|
||||
if (mantissa)
|
||||
{
|
||||
if (exp)
|
||||
{
|
||||
return PPC_FPCLASS_QNAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Denormalized number.
|
||||
return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD;
|
||||
}
|
||||
}
|
||||
else if (exp)
|
||||
{
|
||||
//Infinite
|
||||
return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Zero
|
||||
return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 ClassifyFloat(float fvalue)
|
||||
{
|
||||
// TODO: Optimize the below to be as fast as possible.
|
||||
IntFloat value;
|
||||
value.f = fvalue;
|
||||
u32 sign = value.i & FLOAT_SIGN;
|
||||
u32 exp = value.i & FLOAT_EXP;
|
||||
if (exp > FLOAT_ZERO && exp < FLOAT_EXP)
|
||||
{
|
||||
// Nice normalized number.
|
||||
return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 mantissa = value.i & FLOAT_FRAC;
|
||||
if (mantissa)
|
||||
{
|
||||
if (exp)
|
||||
{
|
||||
return PPC_FPCLASS_QNAN; // Quiet NAN
|
||||
}
|
||||
else
|
||||
{
|
||||
// Denormalized number.
|
||||
return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD;
|
||||
}
|
||||
}
|
||||
else if (exp)
|
||||
{
|
||||
// Infinite
|
||||
return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Zero
|
||||
return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
void LoadDefaultSSEState()
|
||||
{
|
||||
#ifdef USE_SSE
|
||||
_mm_setcsr(default_sse_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void LoadSSEState()
|
||||
{
|
||||
#ifdef USE_SSE
|
||||
_mm_setcsr(saved_sse_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SaveSSEState()
|
||||
{
|
||||
#ifdef USE_SSE
|
||||
saved_sse_state = _mm_getcsr();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void MatrixMul(int n, const float *a, const float *b, float *result)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
for (int j = 0; j < n; ++j)
|
||||
{
|
||||
float temp = 0;
|
||||
for (int k = 0; k < n; ++k)
|
||||
{
|
||||
temp += a[i * n + k] * b[k * n + j];
|
||||
}
|
||||
result[i * n + j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate sum of a float list
|
||||
float MathFloatVectorSum(const std::vector<float>& Vec)
|
||||
{
|
||||
return std::accumulate(Vec.begin(), Vec.end(), 0.0f);
|
||||
}
|
||||
|
||||
void Matrix33::LoadIdentity(Matrix33 &mtx)
|
||||
{
|
||||
memset(mtx.data, 0, sizeof(mtx.data));
|
||||
mtx.data[0] = 1.0f;
|
||||
mtx.data[4] = 1.0f;
|
||||
mtx.data[8] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix33::RotateX(Matrix33 &mtx, float rad)
|
||||
{
|
||||
float s = sin(rad);
|
||||
float c = cos(rad);
|
||||
memset(mtx.data, 0, sizeof(mtx.data));
|
||||
mtx.data[0] = 1;
|
||||
mtx.data[4] = c;
|
||||
mtx.data[5] = -s;
|
||||
mtx.data[7] = s;
|
||||
mtx.data[8] = c;
|
||||
}
|
||||
void Matrix33::RotateY(Matrix33 &mtx, float rad)
|
||||
{
|
||||
float s = sin(rad);
|
||||
float c = cos(rad);
|
||||
memset(mtx.data, 0, sizeof(mtx.data));
|
||||
mtx.data[0] = c;
|
||||
mtx.data[2] = s;
|
||||
mtx.data[4] = 1;
|
||||
mtx.data[6] = -s;
|
||||
mtx.data[8] = c;
|
||||
}
|
||||
|
||||
void Matrix33::Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result)
|
||||
{
|
||||
MatrixMul(3, a.data, b.data, result.data);
|
||||
}
|
||||
|
||||
void Matrix33::Multiply(const Matrix33 &a, const float vec[3], float result[3])
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
result[i] = 0;
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
result[i] += a.data[i * 3 + k] * vec[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Matrix44::LoadIdentity(Matrix44 &mtx)
|
||||
{
|
||||
memset(mtx.data, 0, sizeof(mtx.data));
|
||||
mtx.data[0] = 1.0f;
|
||||
mtx.data[5] = 1.0f;
|
||||
mtx.data[10] = 1.0f;
|
||||
mtx.data[15] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix44::LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
mtx.data[i * 4 + j] = m33.data[i * 3 + j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
mtx.data[i * 4 + 3] = 0;
|
||||
mtx.data[i + 12] = 0;
|
||||
}
|
||||
mtx.data[15] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix44::Set(Matrix44 &mtx, const float mtxArray[16])
|
||||
{
|
||||
for(int i = 0; i < 16; ++i)
|
||||
{
|
||||
mtx.data[i] = mtxArray[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Matrix44::Translate(Matrix44 &mtx, const float vec[3])
|
||||
{
|
||||
LoadIdentity(mtx);
|
||||
mtx.data[3] = vec[0];
|
||||
mtx.data[7] = vec[1];
|
||||
mtx.data[11] = vec[2];
|
||||
}
|
||||
|
||||
void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result)
|
||||
{
|
||||
MatrixMul(4, a.data, b.data, result.data);
|
||||
}
|
||||
|
||||
int Pow2roundup(int x)
|
||||
{
|
||||
if (x < 0)
|
||||
return 0;
|
||||
--x;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return x+1;
|
||||
}
|
||||
|
||||
int GetPow2(int x)
|
||||
{
|
||||
int ret = 0;
|
||||
int val = 1;
|
||||
while(x > val)
|
||||
{
|
||||
ret++;
|
||||
val *= 2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _MATH_UTIL_H_
|
||||
#define _MATH_UTIL_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#if !defined(ARM) && !defined(MIPS)
|
||||
#define USE_SSE
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSE
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MathUtil
|
||||
{
|
||||
|
||||
static const u64 DOUBLE_SIGN = 0x8000000000000000ULL,
|
||||
DOUBLE_EXP = 0x7FF0000000000000ULL,
|
||||
DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL,
|
||||
DOUBLE_ZERO = 0x0000000000000000ULL;
|
||||
|
||||
static const u32 FLOAT_SIGN = 0x80000000,
|
||||
FLOAT_EXP = 0x7F800000,
|
||||
FLOAT_FRAC = 0x007FFFFF,
|
||||
FLOAT_ZERO = 0x00000000;
|
||||
|
||||
union IntDouble {
|
||||
double d;
|
||||
u64 i;
|
||||
};
|
||||
union IntFloat {
|
||||
float f;
|
||||
u32 i;
|
||||
};
|
||||
|
||||
inline bool IsNAN(double d)
|
||||
{
|
||||
IntDouble x; x.d = d;
|
||||
return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
|
||||
((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) );
|
||||
}
|
||||
|
||||
inline bool IsQNAN(double d)
|
||||
{
|
||||
IntDouble x; x.d = d;
|
||||
return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
|
||||
((x.i & 0x0007fffffffffffULL) == 0x000000000000000ULL) &&
|
||||
((x.i & 0x000800000000000ULL) == 0x000800000000000ULL) );
|
||||
}
|
||||
|
||||
inline bool IsSNAN(double d)
|
||||
{
|
||||
IntDouble x; x.d = d;
|
||||
return( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
|
||||
((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) &&
|
||||
((x.i & 0x0008000000000000ULL) == DOUBLE_ZERO) );
|
||||
}
|
||||
|
||||
inline float FlushToZero(float f)
|
||||
{
|
||||
IntFloat x; x.f = f;
|
||||
if ((x.i & FLOAT_EXP) == 0)
|
||||
x.i &= FLOAT_SIGN; // turn into signed zero
|
||||
return x.f;
|
||||
}
|
||||
|
||||
inline double FlushToZeroAsFloat(double d)
|
||||
{
|
||||
IntDouble x; x.d = d;
|
||||
if ((x.i & DOUBLE_EXP) < 0x3800000000000000ULL)
|
||||
x.i &= DOUBLE_SIGN; // turn into signed zero
|
||||
return x.d;
|
||||
}
|
||||
|
||||
enum PPCFpClass
|
||||
{
|
||||
PPC_FPCLASS_QNAN = 0x11,
|
||||
PPC_FPCLASS_NINF = 0x9,
|
||||
PPC_FPCLASS_NN = 0x8,
|
||||
PPC_FPCLASS_ND = 0x18,
|
||||
PPC_FPCLASS_NZ = 0x12,
|
||||
PPC_FPCLASS_PZ = 0x2,
|
||||
PPC_FPCLASS_PD = 0x14,
|
||||
PPC_FPCLASS_PN = 0x4,
|
||||
PPC_FPCLASS_PINF = 0x5,
|
||||
};
|
||||
|
||||
// Uses PowerPC conventions for the return value, so it can be easily
|
||||
// used directly in CPU emulation.
|
||||
u32 ClassifyDouble(double dvalue);
|
||||
// More efficient float version.
|
||||
u32 ClassifyFloat(float fvalue);
|
||||
|
||||
template<class T>
|
||||
struct Rectangle
|
||||
{
|
||||
T left;
|
||||
T top;
|
||||
T right;
|
||||
T bottom;
|
||||
|
||||
Rectangle()
|
||||
{ }
|
||||
|
||||
Rectangle(T theLeft, T theTop, T theRight, T theBottom)
|
||||
: left(theLeft), top(theTop), right(theRight), bottom(theBottom)
|
||||
{ }
|
||||
|
||||
T GetWidth() const { return abs(right - left); }
|
||||
T GetHeight() const { return abs(bottom - top); }
|
||||
|
||||
// If the rectangle is in a coordinate system with a lower-left origin, use
|
||||
// this Clamp.
|
||||
void ClampLL(T x1, T y1, T x2, T y2)
|
||||
{
|
||||
if (left < x1) left = x1;
|
||||
if (right > x2) right = x2;
|
||||
if (top > y1) top = y1;
|
||||
if (bottom < y2) bottom = y2;
|
||||
}
|
||||
|
||||
// If the rectangle is in a coordinate system with an upper-left origin,
|
||||
// use this Clamp.
|
||||
void ClampUL(T x1, T y1, T x2, T y2)
|
||||
{
|
||||
if (left < x1) left = x1;
|
||||
if (right > x2) right = x2;
|
||||
if (top < y1) top = y1;
|
||||
if (bottom > y2) bottom = y2;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace MathUtil
|
||||
|
||||
inline float pow2f(float x) {return x * x;}
|
||||
inline double pow2(double x) {return x * x;}
|
||||
int Pow2roundup(int x);
|
||||
int GetPow2(int x);
|
||||
|
||||
|
||||
/*
|
||||
There are two different flavors of float to int conversion:
|
||||
_mm_cvtps_epi32() and _mm_cvttps_epi32(). The first rounds
|
||||
according to the MXCSR rounding bits. The second one always
|
||||
uses round towards zero.
|
||||
*/
|
||||
|
||||
void SaveSSEState();
|
||||
void LoadSSEState();
|
||||
void LoadDefaultSSEState();
|
||||
float MathFloatVectorSum(const std::vector<float>&);
|
||||
|
||||
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))
|
||||
|
||||
// Tiny matrix/vector library.
|
||||
// Used for things like Free-Look in the gfx backend.
|
||||
|
||||
class Matrix33
|
||||
{
|
||||
public:
|
||||
static void LoadIdentity(Matrix33 &mtx);
|
||||
|
||||
// set mtx to be a rotation matrix around the x axis
|
||||
static void RotateX(Matrix33 &mtx, float rad);
|
||||
// set mtx to be a rotation matrix around the y axis
|
||||
static void RotateY(Matrix33 &mtx, float rad);
|
||||
|
||||
// set result = a x b
|
||||
static void Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result);
|
||||
static void Multiply(const Matrix33 &a, const float vec[3], float result[3]);
|
||||
|
||||
float data[9];
|
||||
};
|
||||
|
||||
class Matrix44
|
||||
{
|
||||
public:
|
||||
static void LoadIdentity(Matrix44 &mtx);
|
||||
static void LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33);
|
||||
static void Set(Matrix44 &mtx, const float mtxArray[16]);
|
||||
|
||||
static void Translate(Matrix44 &mtx, const float vec[3]);
|
||||
|
||||
static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result);
|
||||
|
||||
float data[16];
|
||||
};
|
||||
|
||||
#endif // _MATH_UTIL_H_
|
|
@ -0,0 +1,414 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "MemoryUtil.h"
|
||||
#include "MemArena.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#ifdef ANDROID
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/ashmem.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
// Hopefully this ABI will never change...
|
||||
|
||||
|
||||
#define ASHMEM_DEVICE "/dev/ashmem"
|
||||
|
||||
/*
|
||||
* ashmem_create_region - creates a new ashmem region and returns the file
|
||||
* descriptor, or <0 on error
|
||||
*
|
||||
* `name' is an optional label to give the region (visible in /proc/pid/maps)
|
||||
* `size' is the size of the region, in page-aligned bytes
|
||||
*/
|
||||
int ashmem_create_region(const char *name, size_t size)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
fd = open(ASHMEM_DEVICE, O_RDWR);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (name) {
|
||||
char buf[ASHMEM_NAME_LEN];
|
||||
|
||||
strncpy(buf, name, sizeof(buf));
|
||||
ret = ioctl(fd, ASHMEM_SET_NAME, buf);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, ASHMEM_SET_SIZE, size);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
return fd;
|
||||
|
||||
error:
|
||||
ERROR_LOG(MEMMAP, "NASTY ASHMEM ERROR: ret = %08x", ret);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ashmem_set_prot_region(int fd, int prot)
|
||||
{
|
||||
return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
|
||||
}
|
||||
|
||||
int ashmem_pin_region(int fd, size_t offset, size_t len)
|
||||
{
|
||||
struct ashmem_pin pin = { offset, len };
|
||||
return ioctl(fd, ASHMEM_PIN, &pin);
|
||||
}
|
||||
|
||||
int ashmem_unpin_region(int fd, size_t offset, size_t len)
|
||||
{
|
||||
struct ashmem_pin pin = { offset, len };
|
||||
return ioctl(fd, ASHMEM_UNPIN, &pin);
|
||||
}
|
||||
#endif // Android
|
||||
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
// do not make this "static"
|
||||
#if defined(MAEMO) || defined(MEEGO_EDITION_HARMATTAN)
|
||||
std::string ram_temp_file = "/home/user/gc_mem.tmp";
|
||||
#else
|
||||
std::string ram_temp_file = "/tmp/gc_mem.tmp";
|
||||
#endif
|
||||
#else
|
||||
SYSTEM_INFO sysInfo;
|
||||
#endif
|
||||
|
||||
|
||||
// Windows mappings need to be on 64K boundaries, due to Alpha legacy.
|
||||
#ifdef _WIN32
|
||||
size_t roundup(size_t x) {
|
||||
int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000;
|
||||
return (x + gran - 1) & ~(gran - 1);
|
||||
}
|
||||
#else
|
||||
size_t roundup(size_t x) {
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void MemArena::GrabLowMemSpace(size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL);
|
||||
GetSystemInfo(&sysInfo);
|
||||
#elif defined(ANDROID)
|
||||
// Use ashmem so we don't have to allocate a file on disk!
|
||||
fd = ashmem_create_region("PPSSPP_RAM", size);
|
||||
// Note that it appears that ashmem is pinned by default, so no need to pin.
|
||||
if (fd < 0)
|
||||
{
|
||||
ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode);
|
||||
if (fd < 0)
|
||||
{
|
||||
ERROR_LOG(MEMMAP, "Failed to grab memory space as a file: %s of size: %08x errno: %d", ram_temp_file.c_str(), (int)size, (int)(errno));
|
||||
return;
|
||||
}
|
||||
// delete immediately, we keep the fd so it still lives
|
||||
unlink(ram_temp_file.c_str());
|
||||
if (ftruncate(fd, size) != 0)
|
||||
{
|
||||
ERROR_LOG(MEMMAP, "Failed to ftruncate %d to size %08x", (int)fd, (int)size);
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void MemArena::ReleaseSpace()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(hMemoryMapping);
|
||||
hMemoryMapping = 0;
|
||||
#elif defined(__SYMBIAN32__)
|
||||
memmap->Close();
|
||||
delete memmap;
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void *MemArena::CreateView(s64 offset, size_t size, void *base)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
size = roundup(size);
|
||||
void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base);
|
||||
return ptr;
|
||||
#else
|
||||
void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED |
|
||||
((base == 0) ? 0 : MAP_FIXED), fd, offset);
|
||||
|
||||
if (retval == MAP_FAILED)
|
||||
{
|
||||
NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed", ram_temp_file.c_str(), (int)fd);
|
||||
return 0;
|
||||
}
|
||||
return retval;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void MemArena::ReleaseView(void* view, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
UnmapViewOfFile(view);
|
||||
#elif defined(__SYMBIAN32__)
|
||||
memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size);
|
||||
#else
|
||||
munmap(view, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __SYMBIAN32__
|
||||
u8* MemArena::Find4GBBase()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
#ifdef _WIN32
|
||||
// 64 bit
|
||||
u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
return base;
|
||||
#else
|
||||
// Very precarious - mmap cannot return an error when trying to map already used pages.
|
||||
// This makes the Windows approach above unusable on Linux, so we will simply pray...
|
||||
return reinterpret_cast<u8*>(0x2300000000ULL);
|
||||
#endif
|
||||
|
||||
#else // 32 bit
|
||||
|
||||
#ifdef _WIN32
|
||||
// The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
|
||||
u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
if (base) {
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
}
|
||||
return base;
|
||||
#else
|
||||
void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_SHARED, -1, 0);
|
||||
if (base == MAP_FAILED) {
|
||||
PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
munmap(base, 0x10000000);
|
||||
return static_cast<u8*>(base);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// yeah, this could also be done in like two bitwise ops...
|
||||
#define SKIP(a_flags, b_flags)
|
||||
// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY))
|
||||
// continue;
|
||||
// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))
|
||||
// continue;
|
||||
|
||||
|
||||
|
||||
static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) {
|
||||
// OK, we know where to find free space. Now grab it!
|
||||
// We just mimic the popular BAT setup.
|
||||
size_t position = 0;
|
||||
size_t last_position = 0;
|
||||
|
||||
// Zero all the pointers to be sure.
|
||||
for (int i = 0; i < num_views; i++)
|
||||
{
|
||||
if (views[i].out_ptr_low)
|
||||
*views[i].out_ptr_low = 0;
|
||||
if (views[i].out_ptr)
|
||||
*views[i].out_ptr = 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < num_views; i++)
|
||||
{
|
||||
const MemoryView &view = views[i];
|
||||
SKIP(flags, view.flags);
|
||||
if (view.flags & MV_MIRROR_PREVIOUS) {
|
||||
position = last_position;
|
||||
} else {
|
||||
#ifdef __SYMBIAN32__
|
||||
*(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address);
|
||||
arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size);
|
||||
}
|
||||
*(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF);
|
||||
#else
|
||||
*(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size);
|
||||
if (!*view.out_ptr_low)
|
||||
goto bail;
|
||||
}
|
||||
#ifdef _M_X64
|
||||
*view.out_ptr = (u8*)arena->CreateView(
|
||||
position, view.size, base + view.virtual_address);
|
||||
#else
|
||||
if (view.flags & MV_MIRROR_PREVIOUS) { // TODO: should check if the two & 0x3FFFFFFF are identical.
|
||||
// No need to create multiple identical views.
|
||||
*view.out_ptr = *views[i - 1].out_ptr;
|
||||
} else {
|
||||
*view.out_ptr = (u8*)arena->CreateView(
|
||||
position, view.size, base + (view.virtual_address & 0x3FFFFFFF));
|
||||
if (!*view.out_ptr)
|
||||
goto bail;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
last_position = position;
|
||||
position += roundup(view.size);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
bail:
|
||||
// Argh! ERROR! Free what we grabbed so far so we can try again.
|
||||
for (int j = 0; j <= i; j++)
|
||||
{
|
||||
SKIP(flags, views[i].flags);
|
||||
if (views[j].out_ptr_low && *views[j].out_ptr_low)
|
||||
{
|
||||
arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
|
||||
*views[j].out_ptr_low = NULL;
|
||||
}
|
||||
if (*views[j].out_ptr)
|
||||
{
|
||||
#ifdef _M_X64
|
||||
arena->ReleaseView(*views[j].out_ptr, views[j].size);
|
||||
#else
|
||||
if (!(views[j].flags & MV_MIRROR_PREVIOUS))
|
||||
{
|
||||
arena->ReleaseView(*views[j].out_ptr, views[j].size);
|
||||
}
|
||||
#endif
|
||||
*views[j].out_ptr = NULL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
|
||||
{
|
||||
size_t total_mem = 0;
|
||||
int base_attempts = 0;
|
||||
|
||||
for (int i = 0; i < num_views; i++)
|
||||
{
|
||||
SKIP(flags, views[i].flags);
|
||||
if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0)
|
||||
total_mem += roundup(views[i].size);
|
||||
}
|
||||
// Grab some pagefile backed memory out of the void ...
|
||||
#ifndef __SYMBIAN32__
|
||||
arena->GrabLowMemSpace(total_mem);
|
||||
#endif
|
||||
|
||||
// Now, create views in high memory where there's plenty of space.
|
||||
#ifdef _M_X64
|
||||
u8 *base = MemArena::Find4GBBase();
|
||||
// This really shouldn't fail - in 64-bit, there will always be enough
|
||||
// address space.
|
||||
if (!Memory_TryBase(base, views, num_views, flags, arena))
|
||||
{
|
||||
PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
// Try a whole range of possible bases. Return once we got a valid one.
|
||||
u32 max_base_addr = 0x7FFF0000 - 0x10000000;
|
||||
u8 *base = NULL;
|
||||
|
||||
for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000)
|
||||
{
|
||||
base_attempts++;
|
||||
base = (u8 *)base_addr;
|
||||
if (Memory_TryBase(base, views, num_views, flags, arena))
|
||||
{
|
||||
INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts);
|
||||
base_attempts = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif defined(__SYMBIAN32__)
|
||||
arena->memmap = new RChunk();
|
||||
arena->memmap->CreateDisconnectedLocal(0 , 0, 0x10000000);
|
||||
if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena))
|
||||
{
|
||||
PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
u8* base = arena->memmap->Base();
|
||||
#else
|
||||
// Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors.
|
||||
u8 *base = MemArena::Find4GBBase();
|
||||
if (!Memory_TryBase(base, views, num_views, flags, arena))
|
||||
{
|
||||
PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
if (base_attempts)
|
||||
PanicAlert("No possible memory base pointer found!");
|
||||
return base;
|
||||
}
|
||||
|
||||
void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
|
||||
{
|
||||
for (int i = 0; i < num_views; i++)
|
||||
{
|
||||
SKIP(flags, views[i].flags);
|
||||
if (views[i].out_ptr_low && *views[i].out_ptr_low)
|
||||
arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
|
||||
if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
|
||||
arena->ReleaseView(*views[i].out_ptr, views[i].size);
|
||||
*views[i].out_ptr = NULL;
|
||||
if (views[i].out_ptr_low)
|
||||
*views[i].out_ptr_low = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _MEMARENA_H_
|
||||
#define _MEMARENA_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef __SYMBIAN32__
|
||||
#include <e32std.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
// This class lets you create a block of anonymous RAM, and then arbitrarily map views into it.
|
||||
// Multiple views can mirror the same section of the block, which makes it very convient for emulating
|
||||
// memory mirrors.
|
||||
|
||||
class MemArena
|
||||
{
|
||||
public:
|
||||
void GrabLowMemSpace(size_t size);
|
||||
void ReleaseSpace();
|
||||
void *CreateView(s64 offset, size_t size, void *base = 0);
|
||||
void ReleaseView(void *view, size_t size);
|
||||
|
||||
#ifdef __SYMBIAN32__
|
||||
RChunk* memmap;
|
||||
#else
|
||||
// This only finds 1 GB in 32-bit
|
||||
static u8 *Find4GBBase();
|
||||
#endif
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hMemoryMapping;
|
||||
#else
|
||||
int fd;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum {
|
||||
MV_MIRROR_PREVIOUS = 1,
|
||||
// MV_FAKE_VMEM = 2,
|
||||
// MV_WII_ONLY = 4,
|
||||
};
|
||||
|
||||
struct MemoryView
|
||||
{
|
||||
u8 **out_ptr_low;
|
||||
u8 **out_ptr;
|
||||
u32 virtual_address;
|
||||
u32 size;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
// Uses a memory arena to set up an emulator-friendly memory map according to
|
||||
// a passed-in list of MemoryView structures.
|
||||
u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena);
|
||||
void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena);
|
||||
|
||||
#endif // _MEMARENA_H_
|
|
@ -0,0 +1,245 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "MemoryUtil.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
#include <unistd.h>
|
||||
#ifdef __APPLE__
|
||||
#define PAGE_MASK (4096-1)
|
||||
#else
|
||||
#define PAGE_MASK (getpagesize() - 1)
|
||||
#endif
|
||||
#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
|
||||
#endif
|
||||
|
||||
#ifdef __SYMBIAN32__
|
||||
#include <e32std.h>
|
||||
#define SYMBIAN_CODECHUNK_SIZE 1024*1024*17;
|
||||
static RChunk* g_code_chunk = NULL;
|
||||
static RHeap* g_code_heap = NULL;
|
||||
#endif
|
||||
|
||||
// This is purposely not a full wrapper for virtualalloc/mmap, but it
|
||||
// provides exactly the primitive operations that Dolphin needs.
|
||||
|
||||
void* AllocateExecutableMemory(size_t size, bool low)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#elif defined(__SYMBIAN32__)
|
||||
//This function may be called more than once, and we want to create only one big
|
||||
//memory chunk for all the executable code for the JIT
|
||||
void* ptr;
|
||||
if( g_code_chunk == NULL && g_code_heap == NULL)
|
||||
{
|
||||
TInt minsize = SYMBIAN_CODECHUNK_SIZE;
|
||||
TInt maxsize = SYMBIAN_CODECHUNK_SIZE + 3*GetPageSize(); //some offsets
|
||||
g_code_chunk = new RChunk();
|
||||
g_code_chunk->CreateLocalCode(minsize, maxsize);
|
||||
g_code_heap = UserHeap::ChunkHeap(*g_code_chunk, minsize, 1, maxsize);
|
||||
ptr = (void*) g_code_heap->Alloc( size );
|
||||
}
|
||||
else
|
||||
ptr = g_code_heap->Base();
|
||||
#else
|
||||
static char *map_hint = 0;
|
||||
#if defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
// This OS has no flag to enforce allocation below the 4 GB boundary,
|
||||
// but if we hint that we want a low address it is very likely we will
|
||||
// get one.
|
||||
// An older version of this code used MAP_FIXED, but that has the side
|
||||
// effect of discarding already mapped pages that happen to be in the
|
||||
// requested virtual memory range (such as the emulated RAM, sometimes).
|
||||
if (low && (!map_hint))
|
||||
map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */
|
||||
#endif
|
||||
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANON | MAP_PRIVATE
|
||||
#if defined(__x86_64__) && defined(MAP_32BIT)
|
||||
| (low ? MAP_32BIT : 0)
|
||||
#endif
|
||||
, -1, 0);
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
// printf("Mapped executable memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
if (ptr == MAP_FAILED)
|
||||
{
|
||||
ptr = NULL;
|
||||
#else
|
||||
if (ptr == NULL)
|
||||
{
|
||||
#endif
|
||||
PanicAlert("Failed to allocate executable memory");
|
||||
}
|
||||
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
else
|
||||
{
|
||||
if (low)
|
||||
{
|
||||
map_hint += size;
|
||||
map_hint = (char*)round_page(map_hint); /* round up to the next page */
|
||||
// printf("Next map will (hopefully) be at %p\n", map_hint);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* AllocateMemoryPages(size_t size)
|
||||
{
|
||||
size = (size + 4095) & (~4095);
|
||||
#ifdef _WIN32
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
#elif defined(__SYMBIAN32__)
|
||||
void* ptr = new u8[size];
|
||||
#else
|
||||
void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
#endif
|
||||
|
||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
if (ptr == NULL)
|
||||
PanicAlert("Failed to allocate raw memory");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* AllocateAlignedMemory(size_t size,size_t alignment)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void* ptr = _aligned_malloc(size,alignment);
|
||||
#else
|
||||
void* ptr = NULL;
|
||||
#ifdef ANDROID
|
||||
ptr = memalign(alignment, size);
|
||||
#elif defined(__SYMBIAN32__)
|
||||
// On Symbian, we will want to create an RChunk Allocator.
|
||||
// See: javascriptcore:JavaScriptCore/wtf/symbian/BlockAllocatorSymbian.cpp
|
||||
ptr = malloc(size);
|
||||
#else
|
||||
if(posix_memalign(&ptr, alignment, size) != 0)
|
||||
ptr = NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
if (ptr == NULL)
|
||||
PanicAlert("Failed to allocate aligned memory");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void FreeMemoryPages(void* ptr, size_t size)
|
||||
{
|
||||
size = (size + 4095) & (~4095);
|
||||
if (ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
||||
PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
|
||||
ptr = NULL; // Is this our responsibility?
|
||||
#elif defined(__SYMBIAN32__)
|
||||
delete [] ptr;
|
||||
#else
|
||||
munmap(ptr, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void FreeAlignedMemory(void* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
|
||||
PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
|
||||
PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string MemUsage()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "psapi")
|
||||
DWORD processID = GetCurrentProcessId();
|
||||
HANDLE hProcess;
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
std::string Ret;
|
||||
|
||||
// Print information about the memory usage of the process.
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
|
||||
if (NULL == hProcess) return "MemUsage Error";
|
||||
|
||||
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
|
||||
Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
|
||||
|
||||
CloseHandle(hProcess);
|
||||
return Ret;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _MEMORYUTIL_H
|
||||
#define _MEMORYUTIL_H
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
void* AllocateExecutableMemory(size_t size, bool low = true);
|
||||
void* AllocateMemoryPages(size_t size);
|
||||
void FreeMemoryPages(void* ptr, size_t size);
|
||||
void* AllocateAlignedMemory(size_t size,size_t alignment);
|
||||
void FreeAlignedMemory(void* ptr);
|
||||
void WriteProtectMemory(void* ptr, size_t size, bool executable = false);
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
|
||||
std::string MemUsage();
|
||||
|
||||
inline int GetPageSize() { return 4096; }
|
||||
|
||||
template <typename T>
|
||||
class SimpleBuf {
|
||||
public:
|
||||
SimpleBuf() : buf_(NULL), size_(0) {
|
||||
}
|
||||
|
||||
SimpleBuf(size_t size) : buf_(NULL) {
|
||||
resize(size);
|
||||
}
|
||||
|
||||
~SimpleBuf() {
|
||||
if (buf_ != NULL) {
|
||||
FreeMemoryPages(buf_, size_ * sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
inline T &operator[](size_t index) {
|
||||
return buf_[index];
|
||||
}
|
||||
|
||||
// Doesn't preserve contents.
|
||||
void resize(size_t size) {
|
||||
if (size_ < size) {
|
||||
if (buf_ != NULL) {
|
||||
FreeMemoryPages(buf_, size_ * sizeof(T));
|
||||
}
|
||||
buf_ = (T *)AllocateMemoryPages(size * sizeof(T));
|
||||
size_ = size;
|
||||
}
|
||||
}
|
||||
|
||||
T *data() {
|
||||
return buf_;
|
||||
}
|
||||
|
||||
size_t size() {
|
||||
return size_;
|
||||
}
|
||||
|
||||
private:
|
||||
T *buf_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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"
|
||||
|
||||
#if defined(__APPLE__) || defined(__SYMBIAN32__)
|
||||
#define __thread
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Generic function to get last error message.
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
const char* GetLastErrorMsg()
|
||||
{
|
||||
static const size_t buff_size = 255;
|
||||
|
||||
#ifdef _WIN32
|
||||
static __declspec(thread) char err_str[buff_size] = {};
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
err_str, buff_size, NULL);
|
||||
#else
|
||||
static __thread char err_str[buff_size] = {};
|
||||
|
||||
// Thread safe (XSI-compliant)
|
||||
strerror_r(errno, err_str, buff_size);
|
||||
#endif
|
||||
|
||||
return err_str;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 <stdio.h> // System
|
||||
|
||||
#include "Common.h" // Local
|
||||
#include "StringUtils.h"
|
||||
|
||||
bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style);
|
||||
static MsgAlertHandler msg_handler = DefaultMsgHandler;
|
||||
static bool AlertEnabled = true;
|
||||
|
||||
std::string DefaultStringTranslator(const char* text);
|
||||
static StringTranslator str_translator = DefaultStringTranslator;
|
||||
|
||||
// Select which of these functions that are used for message boxes. If
|
||||
// wxWidgets is enabled we will use wxMsgAlert() that is defined in Main.cpp
|
||||
void RegisterMsgAlertHandler(MsgAlertHandler handler)
|
||||
{
|
||||
msg_handler = handler;
|
||||
}
|
||||
|
||||
// Select translation function. For wxWidgets use wxStringTranslator in Main.cpp
|
||||
void RegisterStringTranslator(StringTranslator translator)
|
||||
{
|
||||
str_translator = translator;
|
||||
}
|
||||
|
||||
// enable/disable the alert handler
|
||||
void SetEnableAlert(bool enable)
|
||||
{
|
||||
AlertEnabled = enable;
|
||||
}
|
||||
|
||||
// This is the first stop for gui alerts where the log is updated and the
|
||||
// correct window is shown
|
||||
bool MsgAlert(bool yes_no, int Style, const char* format, ...)
|
||||
{
|
||||
// Read message and write it to the log
|
||||
std::string caption;
|
||||
char buffer[2048];
|
||||
|
||||
static std::string info_caption;
|
||||
static std::string warn_caption;
|
||||
static std::string ques_caption;
|
||||
static std::string crit_caption;
|
||||
|
||||
if (!info_caption.length())
|
||||
{
|
||||
info_caption = str_translator(_trans("Information"));
|
||||
ques_caption = str_translator(_trans("Question"));
|
||||
warn_caption = str_translator(_trans("Warning"));
|
||||
crit_caption = str_translator(_trans("Critical"));
|
||||
}
|
||||
|
||||
switch(Style)
|
||||
{
|
||||
case INFORMATION:
|
||||
caption = info_caption;
|
||||
break;
|
||||
case QUESTION:
|
||||
caption = ques_caption;
|
||||
break;
|
||||
case WARNING:
|
||||
caption = warn_caption;
|
||||
break;
|
||||
case CRITICAL:
|
||||
caption = crit_caption;
|
||||
break;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args);
|
||||
va_end(args);
|
||||
|
||||
ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer);
|
||||
|
||||
// Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored
|
||||
if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL))
|
||||
return msg_handler(caption.c_str(), buffer, yes_no, Style);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Default non library dependent panic alert
|
||||
bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int STYLE = MB_ICONINFORMATION;
|
||||
if (Style == QUESTION) STYLE = MB_ICONQUESTION;
|
||||
if (Style == WARNING) STYLE = MB_ICONWARNING;
|
||||
|
||||
return IDYES == MessageBox(0, text, caption, STYLE | (yes_no ? MB_YESNO : MB_OK));
|
||||
|
||||
#else
|
||||
printf("%s\n", text);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Default (non) translator
|
||||
std::string DefaultStringTranslator(const char* text)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _MSGHANDLER_H_
|
||||
#define _MSGHANDLER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
// Message alerts
|
||||
enum MSG_TYPE
|
||||
{
|
||||
INFORMATION,
|
||||
QUESTION,
|
||||
WARNING,
|
||||
CRITICAL
|
||||
};
|
||||
|
||||
typedef bool (*MsgAlertHandler)(const char* caption, const char* text,
|
||||
bool yes_no, int Style);
|
||||
typedef std::string (*StringTranslator)(const char* text);
|
||||
|
||||
void RegisterMsgAlertHandler(MsgAlertHandler handler);
|
||||
void RegisterStringTranslator(StringTranslator translator);
|
||||
|
||||
extern bool MsgAlert(bool yes_no, int Style, const char* format, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 3, 4)))
|
||||
#endif
|
||||
;
|
||||
void SetEnableAlert(bool enable);
|
||||
|
||||
#ifndef GEKKO
|
||||
#ifdef _WIN32
|
||||
#define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__)
|
||||
#define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__)
|
||||
#define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__)
|
||||
#define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__)
|
||||
#define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__)
|
||||
// Use these macros (that do the same thing) if the message should be translated.
|
||||
#define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__)
|
||||
#define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__)
|
||||
#define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__)
|
||||
#define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__)
|
||||
#define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__)
|
||||
#else
|
||||
#define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__)
|
||||
#define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__)
|
||||
#define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__)
|
||||
#define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__)
|
||||
#define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__)
|
||||
// Use these macros (that do the same thing) if the message should be translated.
|
||||
#define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__)
|
||||
#define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__)
|
||||
#define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__)
|
||||
#define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__)
|
||||
#define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__)
|
||||
#endif
|
||||
#else
|
||||
// GEKKO
|
||||
#define SuccessAlert(format, ...) ;
|
||||
#define PanicAlert(format, ...) ;
|
||||
#define PanicYesNo(format, ...) ;
|
||||
#define AskYesNo(format, ...) ;
|
||||
#define CriticalAlert(format, ...) ;
|
||||
#define SuccessAlertT(format, ...) ;
|
||||
#define PanicAlertT(format, ...) ;
|
||||
#define PanicYesNoT(format, ...) ;
|
||||
#define AskYesNoT(format, ...) ;
|
||||
#define CriticalAlertT(format, ...) ;
|
||||
#endif
|
||||
|
||||
#endif // _MSGHANDLER_H_
|
|
@ -0,0 +1,41 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _SETUP_H_
|
||||
#define _SETUP_H_
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// File description:
|
||||
// Compilation settings. I avoid placing this in Common.h or some place where lots of files needs
|
||||
// to be rebuilt if any of these settings are changed. I'd rather have it in as few files as possible.
|
||||
// This file can be kept on the ignore list in your SVN program. It allows local optional settings
|
||||
// depending on what works on your computer.
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// Settings:
|
||||
|
||||
// This may remove sound artifacts in Wario Land Shake It and perhaps other games
|
||||
//#define SETUP_AVOID_SOUND_ARTIFACTS
|
||||
|
||||
// Build with playback rerecording options
|
||||
//#define RERECORDING
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
#endif // _SETUP_H_
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
|
||||
#ifndef CONDITION_VARIABLE_H_
|
||||
#define CONDITION_VARIABLE_H_
|
||||
|
||||
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
|
||||
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !defined(ANDROID) && !defined(__SYMBIAN32__)
|
||||
// GCC 4.4 provides <condition_variable>
|
||||
#include <condition_variable>
|
||||
#else
|
||||
|
||||
// partial std::condition_variable implementation for win32/pthread
|
||||
|
||||
#include "StdMutex.h"
|
||||
|
||||
#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
|
||||
#define USE_RVALUE_REFERENCES
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
#define USE_CONDITION_VARIABLES
|
||||
#elif defined(_WIN32)
|
||||
#define USE_EVENTS
|
||||
#endif
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
class condition_variable
|
||||
{
|
||||
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
|
||||
typedef CONDITION_VARIABLE native_type;
|
||||
#elif defined(_WIN32)
|
||||
typedef HANDLE native_type;
|
||||
#else
|
||||
typedef pthread_cond_t native_type;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
#ifdef USE_EVENTS
|
||||
typedef native_type native_handle_type;
|
||||
#else
|
||||
typedef native_type* native_handle_type;
|
||||
#endif
|
||||
|
||||
condition_variable()
|
||||
{
|
||||
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
|
||||
InitializeConditionVariable(&m_handle);
|
||||
#elif defined(_WIN32)
|
||||
m_handle = CreateEvent(NULL, false, false, NULL);
|
||||
#else
|
||||
pthread_cond_init(&m_handle, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
~condition_variable()
|
||||
{
|
||||
#if defined(_WIN32) && !defined(USE_CONDITION_VARIABLES)
|
||||
CloseHandle(m_handle);
|
||||
#elif !defined(_WIN32)
|
||||
pthread_cond_destroy(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
condition_variable(const condition_variable&) /*= delete*/;
|
||||
condition_variable& operator=(const condition_variable&) /*= delete*/;
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
|
||||
WakeConditionVariable(&m_handle);
|
||||
#elif defined(_WIN32)
|
||||
SetEvent(m_handle);
|
||||
#else
|
||||
pthread_cond_signal(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
|
||||
WakeAllConditionVariable(&m_handle);
|
||||
#elif defined(_WIN32)
|
||||
// TODO: broken
|
||||
SetEvent(m_handle);
|
||||
#else
|
||||
pthread_cond_broadcast(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wait(unique_lock<mutex>& lock)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef USE_SRWLOCKS
|
||||
SleepConditionVariableSRW(&m_handle, lock.mutex()->native_handle(), INFINITE, 0);
|
||||
#elif defined(USE_CONDITION_VARIABLES)
|
||||
SleepConditionVariableCS(&m_handle, lock.mutex()->native_handle(), INFINITE);
|
||||
#else
|
||||
// TODO: broken, the unlock and wait need to be atomic
|
||||
lock.unlock();
|
||||
WaitForSingleObject(m_handle, INFINITE);
|
||||
lock.lock();
|
||||
#endif
|
||||
#else
|
||||
pthread_cond_wait(&m_handle, lock.mutex()->native_handle());
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Predicate>
|
||||
void wait(unique_lock<mutex>& lock, Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
wait(lock);
|
||||
}
|
||||
|
||||
//template <class Clock, class Duration>
|
||||
//cv_status wait_until(unique_lock<mutex>& lock,
|
||||
// const chrono::time_point<Clock, Duration>& abs_time);
|
||||
|
||||
//template <class Clock, class Duration, class Predicate>
|
||||
// bool wait_until(unique_lock<mutex>& lock,
|
||||
// const chrono::time_point<Clock, Duration>& abs_time,
|
||||
// Predicate pred);
|
||||
|
||||
//template <class Rep, class Period>
|
||||
//cv_status wait_for(unique_lock<mutex>& lock,
|
||||
// const chrono::duration<Rep, Period>& rel_time);
|
||||
|
||||
//template <class Rep, class Period, class Predicate>
|
||||
// bool wait_for(unique_lock<mutex>& lock,
|
||||
// const chrono::duration<Rep, Period>& rel_time,
|
||||
// Predicate pred);
|
||||
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
#ifdef USE_EVENTS
|
||||
return m_handle;
|
||||
#else
|
||||
return &m_handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
native_type m_handle;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,355 @@
|
|||
|
||||
#ifndef MUTEX_H_
|
||||
#define MUTEX_H_
|
||||
|
||||
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
|
||||
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
|
||||
// Note: __MAC_10_7 is defined on 10.7+.
|
||||
#if (GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ || defined(__APPLE__)) \
|
||||
/* GCC 4.4 provides <mutex>, except on these platforms: */ \
|
||||
&& !defined(ANDROID) && !defined(__SYMBIAN32__) && !defined(IOS) && !defined(MACGNUSTD)
|
||||
#include <mutex>
|
||||
#else
|
||||
|
||||
// partial <mutex> implementation for win32/pthread
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(_WIN32) // WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#else // POSIX
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
|
||||
#define USE_RVALUE_REFERENCES
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
#define USE_SRWLOCKS
|
||||
#endif
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
class recursive_mutex
|
||||
{
|
||||
#ifdef _WIN32
|
||||
typedef CRITICAL_SECTION native_type;
|
||||
#else
|
||||
typedef pthread_mutex_t native_type;
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef native_type* native_handle_type;
|
||||
|
||||
recursive_mutex(const recursive_mutex&) /*= delete*/;
|
||||
recursive_mutex& operator=(const recursive_mutex&) /*= delete*/;
|
||||
|
||||
recursive_mutex()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
InitializeCriticalSection(&m_handle);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&m_handle, &attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
~recursive_mutex()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DeleteCriticalSection(&m_handle);
|
||||
#else
|
||||
pthread_mutex_destroy(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EnterCriticalSection(&m_handle);
|
||||
#else
|
||||
pthread_mutex_lock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LeaveCriticalSection(&m_handle);
|
||||
#else
|
||||
pthread_mutex_unlock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (0 != TryEnterCriticalSection(&m_handle));
|
||||
#else
|
||||
return !pthread_mutex_trylock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m_handle;
|
||||
}
|
||||
|
||||
private:
|
||||
native_type m_handle;
|
||||
};
|
||||
|
||||
#if !defined(_WIN32) || defined(USE_SRWLOCKS)
|
||||
|
||||
class mutex
|
||||
{
|
||||
#ifdef _WIN32
|
||||
typedef SRWLOCK native_type;
|
||||
#else
|
||||
typedef pthread_mutex_t native_type;
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef native_type* native_handle_type;
|
||||
|
||||
mutex(const mutex&) /*= delete*/;
|
||||
mutex& operator=(const mutex&) /*= delete*/;
|
||||
|
||||
mutex()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
InitializeSRWLock(&m_handle);
|
||||
#else
|
||||
pthread_mutex_init(&m_handle, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
~mutex()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#else
|
||||
pthread_mutex_destroy(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
AcquireSRWLockExclusive(&m_handle);
|
||||
#else
|
||||
pthread_mutex_lock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ReleaseSRWLockExclusive(&m_handle);
|
||||
#else
|
||||
pthread_mutex_unlock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// XXX TryAcquireSRWLockExclusive requires Windows 7!
|
||||
// return (0 != TryAcquireSRWLockExclusive(&m_handle));
|
||||
return false;
|
||||
#else
|
||||
return !pthread_mutex_trylock(&m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m_handle;
|
||||
}
|
||||
|
||||
private:
|
||||
native_type m_handle;
|
||||
};
|
||||
|
||||
#else
|
||||
typedef recursive_mutex mutex; // just use CriticalSections
|
||||
|
||||
#endif
|
||||
|
||||
enum defer_lock_t { defer_lock };
|
||||
enum try_to_lock_t { try_to_lock };
|
||||
enum adopt_lock_t { adopt_lock };
|
||||
|
||||
template <class Mutex>
|
||||
class lock_guard
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
explicit lock_guard(mutex_type& m)
|
||||
: pm(m)
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
|
||||
lock_guard(mutex_type& m, adopt_lock_t)
|
||||
: pm(m)
|
||||
{
|
||||
}
|
||||
|
||||
~lock_guard()
|
||||
{
|
||||
pm.unlock();
|
||||
}
|
||||
|
||||
lock_guard(lock_guard const&) /*= delete*/;
|
||||
lock_guard& operator=(lock_guard const&) /*= delete*/;
|
||||
|
||||
private:
|
||||
mutex_type& pm;
|
||||
};
|
||||
|
||||
template <class Mutex>
|
||||
class unique_lock
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
unique_lock()
|
||||
: pm(NULL), owns(false)
|
||||
{}
|
||||
|
||||
/*explicit*/ unique_lock(mutex_type& m)
|
||||
: pm(&m), owns(true)
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
|
||||
unique_lock(mutex_type& m, defer_lock_t)
|
||||
: pm(&m), owns(false)
|
||||
{}
|
||||
|
||||
unique_lock(mutex_type& m, try_to_lock_t)
|
||||
: pm(&m), owns(m.try_lock())
|
||||
{}
|
||||
|
||||
unique_lock(mutex_type& m, adopt_lock_t)
|
||||
: pm(&m), owns(true)
|
||||
{}
|
||||
|
||||
//template <class Clock, class Duration>
|
||||
//unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
|
||||
|
||||
//template <class Rep, class Period>
|
||||
//unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
|
||||
|
||||
~unique_lock()
|
||||
{
|
||||
if (owns_lock())
|
||||
mutex()->unlock();
|
||||
}
|
||||
|
||||
#ifdef USE_RVALUE_REFERENCES
|
||||
unique_lock& operator=(const unique_lock&) /*= delete*/;
|
||||
|
||||
unique_lock& operator=(unique_lock&& other)
|
||||
{
|
||||
#else
|
||||
unique_lock& operator=(const unique_lock& u)
|
||||
{
|
||||
// ugly const_cast to get around lack of rvalue references
|
||||
unique_lock& other = const_cast<unique_lock&>(u);
|
||||
#endif
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef USE_RVALUE_REFERENCES
|
||||
unique_lock(const unique_lock&) /*= delete*/;
|
||||
|
||||
unique_lock(unique_lock&& other)
|
||||
: pm(NULL), owns(false)
|
||||
{
|
||||
#else
|
||||
unique_lock(const unique_lock& u)
|
||||
: pm(NULL), owns(false)
|
||||
{
|
||||
// ugly const_cast to get around lack of rvalue references
|
||||
unique_lock& other = const_cast<unique_lock&>(u);
|
||||
#endif
|
||||
swap(other);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
mutex()->lock();
|
||||
owns = true;
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
owns = mutex()->try_lock();
|
||||
return owns;
|
||||
}
|
||||
|
||||
//template <class Rep, class Period>
|
||||
//bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
//template <class Clock, class Duration>
|
||||
//bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
|
||||
void unlock()
|
||||
{
|
||||
mutex()->unlock();
|
||||
owns = false;
|
||||
}
|
||||
|
||||
void swap(unique_lock& u)
|
||||
{
|
||||
std::swap(pm, u.pm);
|
||||
std::swap(owns, u.owns);
|
||||
}
|
||||
|
||||
mutex_type* release()
|
||||
{
|
||||
mutex_type* const ret = mutex();
|
||||
|
||||
pm = NULL;
|
||||
owns = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool owns_lock() const
|
||||
{
|
||||
return owns;
|
||||
}
|
||||
|
||||
//explicit operator bool () const
|
||||
//{
|
||||
// return owns_lock();
|
||||
//}
|
||||
|
||||
mutex_type* mutex() const
|
||||
{
|
||||
return pm;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex_type* pm;
|
||||
bool owns;
|
||||
};
|
||||
|
||||
template <class Mutex>
|
||||
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,310 @@
|
|||
|
||||
#ifndef STD_THREAD_H_
|
||||
#define STD_THREAD_H_
|
||||
|
||||
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
|
||||
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !defined(ANDROID) && !defined(__SYMBIAN32__)
|
||||
// GCC 4.4 provides <thread>
|
||||
#ifndef _GLIBCXX_USE_SCHED_YIELD
|
||||
#define _GLIBCXX_USE_SCHED_YIELD
|
||||
#endif
|
||||
#include <thread>
|
||||
#else
|
||||
|
||||
// partial std::thread implementation for win32/pthread
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
|
||||
#define USE_RVALUE_REFERENCES
|
||||
#endif
|
||||
|
||||
//#ifdef __APPLE__
|
||||
//#import <Foundation/NSAutoreleasePool.h>
|
||||
//#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
// WIN32
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
#if defined(_MSC_VER) && defined(_MT)
|
||||
// When linking with LIBCMT (the multithreaded C library), Microsoft recommends
|
||||
// using _beginthreadex instead of CreateThread.
|
||||
#define USE_BEGINTHREADEX
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_BEGINTHREADEX
|
||||
#define THREAD_ID unsigned
|
||||
#define THREAD_RETURN unsigned __stdcall
|
||||
#else
|
||||
#define THREAD_ID DWORD
|
||||
#define THREAD_RETURN DWORD WINAPI
|
||||
#endif
|
||||
#define THREAD_HANDLE HANDLE
|
||||
|
||||
#else
|
||||
// PTHREAD
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef _POSIX_THREADS
|
||||
#error unsupported platform (no pthreads?)
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define THREAD_ID pthread_t
|
||||
#define THREAD_HANDLE pthread_t
|
||||
#define THREAD_RETURN void*
|
||||
|
||||
#endif
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
class thread
|
||||
{
|
||||
public:
|
||||
typedef THREAD_HANDLE native_handle_type;
|
||||
|
||||
class id
|
||||
{
|
||||
friend class thread;
|
||||
public:
|
||||
id() : m_thread(0) {}
|
||||
id(THREAD_ID _id) : m_thread(_id) {}
|
||||
|
||||
bool operator==(const id& rhs) const
|
||||
{
|
||||
return m_thread == rhs.m_thread;
|
||||
}
|
||||
|
||||
bool operator!=(const id& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const id& rhs) const
|
||||
{
|
||||
return m_thread < rhs.m_thread;
|
||||
}
|
||||
|
||||
private:
|
||||
THREAD_ID m_thread;
|
||||
};
|
||||
|
||||
// no variadic template support in msvc
|
||||
//template <typename C, typename... A>
|
||||
//thread(C&& func, A&&... args);
|
||||
|
||||
template <typename C>
|
||||
thread(C func)
|
||||
{
|
||||
StartThread(new Func<C>(func));
|
||||
}
|
||||
|
||||
template <typename C, typename A>
|
||||
thread(C func, A arg)
|
||||
{
|
||||
StartThread(new FuncArg<C, A>(func, arg));
|
||||
}
|
||||
|
||||
thread() /*= default;*/ {}
|
||||
|
||||
#ifdef USE_RVALUE_REFERENCES
|
||||
thread(const thread&) /*= delete*/;
|
||||
|
||||
thread(thread&& other)
|
||||
{
|
||||
#else
|
||||
thread(const thread& t)
|
||||
{
|
||||
// ugly const_cast to get around lack of rvalue references
|
||||
thread& other = const_cast<thread&>(t);
|
||||
#endif
|
||||
swap(other);
|
||||
}
|
||||
|
||||
#ifdef USE_RVALUE_REFERENCES
|
||||
thread& operator=(const thread&) /*= delete*/;
|
||||
|
||||
thread& operator=(thread&& other)
|
||||
{
|
||||
#else
|
||||
thread& operator=(const thread& t)
|
||||
{
|
||||
// ugly const_cast to get around lack of rvalue references
|
||||
thread& other = const_cast<thread&>(t);
|
||||
#endif
|
||||
if (joinable())
|
||||
detach();
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~thread()
|
||||
{
|
||||
if (joinable())
|
||||
detach();
|
||||
}
|
||||
|
||||
bool joinable() const
|
||||
{
|
||||
return m_id != id();
|
||||
}
|
||||
|
||||
id get_id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return m_handle;
|
||||
#else
|
||||
return m_id.m_thread;
|
||||
#endif
|
||||
}
|
||||
|
||||
void join()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WaitForSingleObject(m_handle, INFINITE);
|
||||
detach();
|
||||
#else
|
||||
pthread_join(m_id.m_thread, NULL);
|
||||
m_id = id();
|
||||
#endif
|
||||
}
|
||||
|
||||
void detach()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(m_handle);
|
||||
#else
|
||||
pthread_detach(m_id.m_thread);
|
||||
#endif
|
||||
m_id = id();
|
||||
}
|
||||
|
||||
void swap(thread& other)
|
||||
{
|
||||
std::swap(m_id, other.m_id);
|
||||
#ifdef _WIN32
|
||||
std::swap(m_handle, other.m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned hardware_concurrency()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo(&sysinfo);
|
||||
return static_cast<unsigned>(sysinfo.dwNumberOfProcessors);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
id m_id;
|
||||
|
||||
#ifdef _WIN32
|
||||
native_handle_type m_handle;
|
||||
#endif
|
||||
|
||||
template <typename F>
|
||||
void StartThread(F* param)
|
||||
{
|
||||
#ifdef USE_BEGINTHREADEX
|
||||
m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete<F>, param, 0, &m_id.m_thread);
|
||||
#elif defined(_WIN32)
|
||||
m_handle = CreateThread(NULL, 0, &RunAndDelete<F>, param, 0, &m_id.m_thread);
|
||||
#else
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setstacksize(&attr, 1024 * 1024);
|
||||
if (pthread_create(&m_id.m_thread, &attr, &RunAndDelete<F>, param))
|
||||
m_id = id();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
class Func
|
||||
{
|
||||
public:
|
||||
Func(C _func) : func(_func) {}
|
||||
|
||||
void Run() { func(); }
|
||||
|
||||
private:
|
||||
C const func;
|
||||
};
|
||||
|
||||
template <typename C, typename A>
|
||||
class FuncArg
|
||||
{
|
||||
public:
|
||||
FuncArg(C _func, A _arg) : func(_func), arg(_arg) {}
|
||||
|
||||
void Run() { func(arg); }
|
||||
|
||||
private:
|
||||
C const func;
|
||||
A arg;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
static THREAD_RETURN RunAndDelete(void* param)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
#endif
|
||||
static_cast<F*>(param)->Run();
|
||||
delete static_cast<F*>(param);
|
||||
#ifdef __APPLE__
|
||||
// [pool release];
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
|
||||
inline void yield()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SwitchToThread();
|
||||
#else
|
||||
sleep(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline thread::id get_id()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return GetCurrentThreadId();
|
||||
#else
|
||||
return pthread_self();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace this_thread
|
||||
|
||||
} // namespace std
|
||||
|
||||
#undef USE_RVALUE_REFERENCES
|
||||
#undef USE_BEGINTHREADEX
|
||||
#undef THREAD_ID
|
||||
#undef THREAD_RETURN
|
||||
#undef THREAD_HANDLE
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
long parseHexLong(std::string s) {
|
||||
long value = 0;
|
||||
|
||||
if (s.substr(0,2) == "0x") {
|
||||
//s = s.substr(2);
|
||||
}
|
||||
value = strtoul(s.c_str(),0, 0);
|
||||
return value;
|
||||
}
|
||||
long parseLong(std::string s) {
|
||||
long value = 0;
|
||||
if (s.substr(0,2) == "0x") {
|
||||
s = s.substr(2);
|
||||
value = strtol(s.c_str(),NULL, 16);
|
||||
} else {
|
||||
value = strtol(s.c_str(),NULL, 10);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
|
||||
{
|
||||
int writtenCount = vsnprintf(out, outsize, format, args);
|
||||
|
||||
if (writtenCount > 0 && writtenCount < outsize)
|
||||
{
|
||||
out[writtenCount] = '\0';
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[outsize - 1] = '\0';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
|
||||
{
|
||||
if (full_path.empty())
|
||||
return false;
|
||||
|
||||
size_t dir_end = full_path.find_last_of("/"
|
||||
// windows needs the : included for something like just "C:" to be considered a directory
|
||||
#ifdef _WIN32
|
||||
":"
|
||||
#endif
|
||||
);
|
||||
if (std::string::npos == dir_end)
|
||||
dir_end = 0;
|
||||
else
|
||||
dir_end += 1;
|
||||
|
||||
size_t fname_end = full_path.rfind('.');
|
||||
if (fname_end < dir_end || std::string::npos == fname_end)
|
||||
fname_end = full_path.size();
|
||||
|
||||
if (_pPath)
|
||||
*_pPath = full_path.substr(0, dir_end);
|
||||
|
||||
if (_pFilename)
|
||||
*_pFilename = full_path.substr(dir_end, fname_end - dir_end);
|
||||
|
||||
if (_pExtension)
|
||||
*_pExtension = full_path.substr(fname_end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename)
|
||||
{
|
||||
_CompleteFilename = _Path;
|
||||
|
||||
// check for seperator
|
||||
if (!strchr(DIR_SEP_CHRS, *_CompleteFilename.rbegin()))
|
||||
_CompleteFilename += DIR_SEP;
|
||||
|
||||
// add the filename
|
||||
_CompleteFilename += _Filename;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _STRINGUTIL_H_
|
||||
#define _STRINGUTIL_H_
|
||||
|
||||
#include <iomanip>
|
||||
#include <base/stringutil.h>
|
||||
|
||||
#include "Common.h"
|
||||
long parseHexLong(std::string s);
|
||||
long parseLong(std::string s);
|
||||
std::string StringFromFormat(const char* format, ...);
|
||||
// Cheap!
|
||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args);
|
||||
|
||||
template<size_t Count>
|
||||
inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
CharArrayFromFormatV(out, Count, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// Thousand separator. Turns 12345678 into 12,345,678
|
||||
template <typename I>
|
||||
std::string ThousandSeparate(I value, int spaces = 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
// std::locale("") seems to be broken on many platforms
|
||||
#if defined _WIN32 || (defined __linux__ && !defined __clang__)
|
||||
oss.imbue(std::locale(""));
|
||||
#endif
|
||||
oss << std::setw(spaces) << value;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string TabsToSpaces(int tab_size, const std::string &in);
|
||||
|
||||
// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe"
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension);
|
||||
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename);
|
||||
|
||||
#endif // _STRINGUTIL_H_
|
|
@ -0,0 +1,192 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "Setup.h"
|
||||
#include "Thread.h"
|
||||
#include "Common.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach.h>
|
||||
#elif defined BSD4_4
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_BEGINTHREADEX
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
||||
int CurrentThreadId()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return GetCurrentThreadId();
|
||||
#elif defined __APPLE__
|
||||
return mach_thread_self();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
{
|
||||
SetThreadAffinityMask(thread, mask);
|
||||
}
|
||||
|
||||
void SetCurrentThreadAffinity(u32 mask)
|
||||
{
|
||||
SetThreadAffinityMask(GetCurrentThread(), mask);
|
||||
}
|
||||
|
||||
// Supporting functions
|
||||
void SleepCurrentThread(int ms)
|
||||
{
|
||||
Sleep(ms);
|
||||
}
|
||||
|
||||
void SwitchCurrentThread()
|
||||
{
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
// Sets the debugger-visible name of the current thread.
|
||||
// Uses undocumented (actually, it is now documented) trick.
|
||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
|
||||
|
||||
// This is implemented much nicer in upcoming msvc++, see:
|
||||
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
|
||||
void SetCurrentThreadName(const char* szThreadName)
|
||||
{
|
||||
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
||||
#pragma pack(push,8)
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // must be 0x1000
|
||||
LPCSTR szName; // pointer to name (in user addr space)
|
||||
DWORD dwThreadID; // thread ID (-1=caller thread)
|
||||
DWORD dwFlags; // reserved for future use, must be zero
|
||||
} info;
|
||||
#pragma pack(pop)
|
||||
|
||||
info.dwType = 0x1000;
|
||||
info.szName = szThreadName;
|
||||
info.dwThreadID = -1; //dwThreadID;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
}
|
||||
__except(EXCEPTION_CONTINUE_EXECUTION)
|
||||
{}
|
||||
}
|
||||
|
||||
void EnableCrashingOnCrashes()
|
||||
{
|
||||
typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
|
||||
typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);
|
||||
const DWORD EXCEPTION_SWALLOWING = 0x1;
|
||||
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32,
|
||||
"GetProcessUserModeExceptionPolicy");
|
||||
tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32,
|
||||
"SetProcessUserModeExceptionPolicy");
|
||||
if (pGetPolicy && pSetPolicy)
|
||||
{
|
||||
DWORD dwFlags;
|
||||
if (pGetPolicy(&dwFlags))
|
||||
{
|
||||
// Turn off the filter
|
||||
pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else // !WIN32, so must be POSIX threads
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
thread_policy_set(pthread_mach_thread_np(thread),
|
||||
THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1);
|
||||
#elif (defined __linux__ || defined BSD4_4) && !defined(ANDROID)
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
|
||||
for (int i = 0; i != sizeof(mask) * 8; ++i)
|
||||
if ((mask >> i) & 1)
|
||||
CPU_SET(i, &cpu_set);
|
||||
|
||||
pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetCurrentThreadAffinity(u32 mask)
|
||||
{
|
||||
SetThreadAffinity(pthread_self(), mask);
|
||||
}
|
||||
|
||||
static pthread_key_t threadname_key;
|
||||
static pthread_once_t threadname_key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
void SleepCurrentThread(int ms)
|
||||
{
|
||||
usleep(1000 * ms);
|
||||
}
|
||||
|
||||
void SwitchCurrentThread()
|
||||
{
|
||||
usleep(1000 * 1);
|
||||
}
|
||||
|
||||
static void FreeThreadName(void* threadname)
|
||||
{
|
||||
free(threadname);
|
||||
}
|
||||
|
||||
static void ThreadnameKeyAlloc()
|
||||
{
|
||||
pthread_key_create(&threadname_key, FreeThreadName);
|
||||
}
|
||||
|
||||
void SetCurrentThreadName(const char* szThreadName)
|
||||
{
|
||||
pthread_once(&threadname_key_once, ThreadnameKeyAlloc);
|
||||
|
||||
void* threadname;
|
||||
if ((threadname = pthread_getspecific(threadname_key)) != NULL)
|
||||
free(threadname);
|
||||
|
||||
pthread_setspecific(threadname_key, strdup(szThreadName));
|
||||
|
||||
INFO_LOG(COMMON, "%s(%s)\n", __FUNCTION__, szThreadName);
|
||||
}
|
||||
|
||||
void EnableCrashingOnCrashes()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Common
|
|
@ -0,0 +1,177 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _THREAD_H_
|
||||
#define _THREAD_H_
|
||||
|
||||
#include "StdThread.h"
|
||||
#include "StdMutex.h"
|
||||
#include "StdConditionVariable.h"
|
||||
|
||||
// Don't include common.h here as it will break LogManager
|
||||
#include "CommonTypes.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// This may not be defined outside _WIN32
|
||||
#ifndef _WIN32
|
||||
#ifndef INFINITE
|
||||
#define INFINITE 0xffffffff
|
||||
#endif
|
||||
|
||||
// Assume !ARM && !MIPS = x86
|
||||
#if !defined(ARM) && !defined(MIPS)
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
//for gettimeofday and struct time(spec|val)
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
||||
int CurrentThreadId();
|
||||
|
||||
// In Windows 7 SP1 or later, stops Windows from swallowing crashes in WndProcs and other callbacks.
|
||||
void EnableCrashingOnCrashes();
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
|
||||
void SetCurrentThreadAffinity(u32 mask);
|
||||
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
Event()
|
||||
: is_set(false)
|
||||
{};
|
||||
|
||||
void Set()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
if (!is_set)
|
||||
{
|
||||
is_set = true;
|
||||
m_condvar.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void Wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
m_condvar.wait(lk, IsSet(this));
|
||||
is_set = false;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
// no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration
|
||||
is_set = false;
|
||||
}
|
||||
|
||||
private:
|
||||
class IsSet
|
||||
{
|
||||
public:
|
||||
IsSet(const Event* ev)
|
||||
: m_event(ev)
|
||||
{}
|
||||
|
||||
bool operator()()
|
||||
{
|
||||
return m_event->is_set;
|
||||
}
|
||||
|
||||
private:
|
||||
const Event* const m_event;
|
||||
};
|
||||
|
||||
volatile bool is_set;
|
||||
std::condition_variable m_condvar;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
// TODO: doesn't work on windows with (count > 2)
|
||||
class Barrier
|
||||
{
|
||||
public:
|
||||
Barrier(size_t count)
|
||||
: m_count(count), m_waiting(0)
|
||||
{}
|
||||
|
||||
// block until "count" threads call Sync()
|
||||
bool Sync()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
|
||||
// TODO: broken when next round of Sync()s
|
||||
// is entered before all waiting threads return from the notify_all
|
||||
|
||||
if (m_count == ++m_waiting)
|
||||
{
|
||||
m_waiting = 0;
|
||||
m_condvar.notify_all();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_condvar.wait(lk, IsDoneWating(this));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class IsDoneWating
|
||||
{
|
||||
public:
|
||||
IsDoneWating(const Barrier* bar)
|
||||
: m_bar(bar)
|
||||
{}
|
||||
|
||||
bool operator()()
|
||||
{
|
||||
return (0 == m_bar->m_waiting);
|
||||
}
|
||||
|
||||
private:
|
||||
const Barrier* const m_bar;
|
||||
};
|
||||
|
||||
std::condition_variable m_condvar;
|
||||
std::mutex m_mutex;
|
||||
const size_t m_count;
|
||||
volatile size_t m_waiting;
|
||||
};
|
||||
|
||||
void SleepCurrentThread(int ms);
|
||||
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
|
||||
|
||||
// Use this function during a spin-wait to make the current thread
|
||||
// relax while another thread is working. This may be more efficient
|
||||
// than using events because event functions use kernel calls.
|
||||
inline void YieldCPU()
|
||||
{
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
void SetCurrentThreadName(const char *name);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif // _THREAD_H_
|
|
@ -0,0 +1,19 @@
|
|||
#include "ThreadPools.h"
|
||||
|
||||
#include "../Core/Config.h"
|
||||
|
||||
std::shared_ptr<ThreadPool> GlobalThreadPool::pool;
|
||||
bool GlobalThreadPool::initialized = false;
|
||||
|
||||
void GlobalThreadPool::Loop(const std::function<void(int,int)>& loop, int lower, int upper) {
|
||||
Inititialize();
|
||||
pool->ParallelLoop(loop, lower, upper);
|
||||
}
|
||||
|
||||
void GlobalThreadPool::Inititialize() {
|
||||
if(!initialized) {
|
||||
pool = std::make_shared<ThreadPool>(g_Config.iNumWorkerThreads);
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "thread/threadpool.h"
|
||||
|
||||
class GlobalThreadPool {
|
||||
public:
|
||||
// will execute slices of "loop" from "lower" to "upper"
|
||||
// in parallel on the global thread pool
|
||||
static void Loop(const std::function<void(int,int)>& loop, int lower, int upper);
|
||||
|
||||
private:
|
||||
static std::shared_ptr<ThreadPool> pool;
|
||||
static bool initialized;
|
||||
static void Inititialize();
|
||||
};
|
|
@ -0,0 +1,143 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 <map>
|
||||
|
||||
#include "Common.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "ABI.h"
|
||||
#include "Thunk.h"
|
||||
|
||||
#define THUNK_ARENA_SIZE 1024*1024*1
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static u8 GC_ALIGNED32(saved_fp_state[16 * 4 * 4]);
|
||||
static u8 GC_ALIGNED32(saved_gpr_state[16 * 8]);
|
||||
static u16 saved_mxcsr;
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
void ThunkManager::Init()
|
||||
{
|
||||
AllocCodeSpace(THUNK_ARENA_SIZE);
|
||||
save_regs = GetCodePtr();
|
||||
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
|
||||
MOVAPS(M(saved_fp_state + i * 16), (X64Reg)(XMM0 + i));
|
||||
STMXCSR(M(&saved_mxcsr));
|
||||
#ifdef _M_X64
|
||||
MOV(64, M(saved_gpr_state + 0 ), R(RCX));
|
||||
MOV(64, M(saved_gpr_state + 8 ), R(RDX));
|
||||
MOV(64, M(saved_gpr_state + 16), R(R8) );
|
||||
MOV(64, M(saved_gpr_state + 24), R(R9) );
|
||||
MOV(64, M(saved_gpr_state + 32), R(R10));
|
||||
MOV(64, M(saved_gpr_state + 40), R(R11));
|
||||
#ifndef _WIN32
|
||||
MOV(64, M(saved_gpr_state + 48), R(RSI));
|
||||
MOV(64, M(saved_gpr_state + 56), R(RDI));
|
||||
#endif
|
||||
MOV(64, M(saved_gpr_state + 64), R(RBX));
|
||||
#else
|
||||
MOV(32, M(saved_gpr_state + 0 ), R(RCX));
|
||||
MOV(32, M(saved_gpr_state + 4 ), R(RDX));
|
||||
#endif
|
||||
RET();
|
||||
load_regs = GetCodePtr();
|
||||
LDMXCSR(M(&saved_mxcsr));
|
||||
for (int i = 2; i < ABI_GetNumXMMRegs(); i++)
|
||||
MOVAPS((X64Reg)(XMM0 + i), M(saved_fp_state + i * 16));
|
||||
#ifdef _M_X64
|
||||
MOV(64, R(RCX), M(saved_gpr_state + 0 ));
|
||||
MOV(64, R(RDX), M(saved_gpr_state + 8 ));
|
||||
MOV(64, R(R8) , M(saved_gpr_state + 16));
|
||||
MOV(64, R(R9) , M(saved_gpr_state + 24));
|
||||
MOV(64, R(R10), M(saved_gpr_state + 32));
|
||||
MOV(64, R(R11), M(saved_gpr_state + 40));
|
||||
#ifndef _WIN32
|
||||
MOV(64, R(RSI), M(saved_gpr_state + 48));
|
||||
MOV(64, R(RDI), M(saved_gpr_state + 56));
|
||||
#endif
|
||||
MOV(64, R(RBX), M(saved_gpr_state + 64));
|
||||
#else
|
||||
MOV(32, R(RCX), M(saved_gpr_state + 0 ));
|
||||
MOV(32, R(RDX), M(saved_gpr_state + 4 ));
|
||||
#endif
|
||||
RET();
|
||||
}
|
||||
|
||||
void ThunkManager::Reset()
|
||||
{
|
||||
thunks.clear();
|
||||
ResetCodePtr();
|
||||
}
|
||||
|
||||
void ThunkManager::Shutdown()
|
||||
{
|
||||
Reset();
|
||||
FreeCodeSpace();
|
||||
}
|
||||
|
||||
void *ThunkManager::ProtectFunction(void *function, int num_params)
|
||||
{
|
||||
std::map<void *, const u8 *>::iterator iter;
|
||||
iter = thunks.find(function);
|
||||
if (iter != thunks.end())
|
||||
return (void *)iter->second;
|
||||
if (!region)
|
||||
PanicAlert("Trying to protect functions before the emu is started. Bad bad bad.");
|
||||
|
||||
const u8 *call_point = GetCodePtr();
|
||||
// Make sure to align stack.
|
||||
#ifdef _M_X64
|
||||
#ifdef _WIN32
|
||||
SUB(64, R(ESP), Imm8(0x28));
|
||||
#else
|
||||
SUB(64, R(ESP), Imm8(0x8));
|
||||
#endif
|
||||
ABI_CallFunction((void*)save_regs);
|
||||
ABI_CallFunction((void*)function);
|
||||
ABI_CallFunction((void*)load_regs);
|
||||
#ifdef _WIN32
|
||||
ADD(64, R(ESP), Imm8(0x28));
|
||||
#else
|
||||
ADD(64, R(ESP), Imm8(0x8));
|
||||
#endif
|
||||
RET();
|
||||
#else
|
||||
CALL((void*)save_regs);
|
||||
// Since parameters are in the previous stack frame, not in registers, this takes some
|
||||
// trickery : we simply re-push the parameters. might not be optimal, but that doesn't really
|
||||
// matter.
|
||||
ABI_AlignStack(num_params * 4);
|
||||
unsigned int alignedSize = ABI_GetAlignedFrameSize(num_params * 4);
|
||||
for (int i = 0; i < num_params; i++) {
|
||||
// ESP is changing, so we do not need i
|
||||
PUSH(32, MDisp(ESP, alignedSize - 4));
|
||||
}
|
||||
CALL(function);
|
||||
ABI_RestoreStack(num_params * 4);
|
||||
CALL((void*)load_regs);
|
||||
RET();
|
||||
#endif
|
||||
|
||||
thunks[function] = call_point;
|
||||
return (void *)call_point;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _THUNK_H_
|
||||
#define _THUNK_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Common.h"
|
||||
#if defined(ARM)
|
||||
#include "ArmEmitter.h"
|
||||
#else
|
||||
#include "x64Emitter.h"
|
||||
#endif
|
||||
|
||||
// This simple class creates a wrapper around a C/C++ function that saves all fp state
|
||||
// before entering it, and restores it upon exit. This is required to be able to selectively
|
||||
// call functions from generated code, without inflicting the performance hit and increase
|
||||
// of complexity that it means to protect the generated code from this problem.
|
||||
|
||||
// This process is called thunking.
|
||||
|
||||
// There will only ever be one level of thunking on the stack, plus,
|
||||
// we don't want to pollute the stack, so we store away regs somewhere global.
|
||||
// NOT THREAD SAFE. This may only be used from the CPU thread.
|
||||
// Any other thread using this stuff will be FATAL.
|
||||
#if defined(ARM)
|
||||
class ThunkManager : public ArmGen::ARMXCodeBlock
|
||||
#else
|
||||
class ThunkManager : public Gen::XCodeBlock
|
||||
#endif
|
||||
{
|
||||
std::map<void *, const u8 *> thunks;
|
||||
|
||||
const u8 *save_regs;
|
||||
const u8 *load_regs;
|
||||
|
||||
public:
|
||||
ThunkManager() {
|
||||
Init();
|
||||
}
|
||||
~ThunkManager() {
|
||||
Shutdown();
|
||||
}
|
||||
void *ProtectFunction(void *function, int num_params);
|
||||
private:
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Reset();
|
||||
};
|
||||
|
||||
#endif // _THUNK_H_
|
|
@ -0,0 +1,246 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <sys/timeb.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "Timer.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
||||
u32 Timer::GetTimeMs()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return timeGetTime();
|
||||
#else
|
||||
struct timeval t;
|
||||
(void)gettimeofday(&t, NULL);
|
||||
return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000));
|
||||
#endif
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
// Initiate, Start, Stop, and Update the time
|
||||
// --------------------------------------------
|
||||
|
||||
// Set initial values for the class
|
||||
Timer::Timer()
|
||||
: m_LastTime(0), m_StartTime(0), m_Running(false)
|
||||
{
|
||||
Update();
|
||||
|
||||
#ifdef _WIN32
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Write the starting time
|
||||
void Timer::Start()
|
||||
{
|
||||
m_StartTime = GetTimeMs();
|
||||
m_Running = true;
|
||||
}
|
||||
|
||||
// Stop the timer
|
||||
void Timer::Stop()
|
||||
{
|
||||
// Write the final time
|
||||
m_LastTime = GetTimeMs();
|
||||
m_Running = false;
|
||||
}
|
||||
|
||||
// Update the last time variable
|
||||
void Timer::Update()
|
||||
{
|
||||
m_LastTime = GetTimeMs();
|
||||
//TODO(ector) - QPF
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
// Get time difference and elapsed time
|
||||
// -------------------------------------
|
||||
|
||||
// Get the number of milliseconds since the last Update()
|
||||
u64 Timer::GetTimeDifference()
|
||||
{
|
||||
return GetTimeMs() - m_LastTime;
|
||||
}
|
||||
|
||||
// Add the time difference since the last Update() to the starting time.
|
||||
// This is used to compensate for a paused game.
|
||||
void Timer::AddTimeDifference()
|
||||
{
|
||||
m_StartTime += GetTimeDifference();
|
||||
}
|
||||
|
||||
// Wind back the starting time to a custom time
|
||||
void Timer::WindBackStartingTime(u64 WindBack)
|
||||
{
|
||||
m_StartTime += WindBack;
|
||||
}
|
||||
|
||||
// Get the time elapsed since the Start()
|
||||
u64 Timer::GetTimeElapsed()
|
||||
{
|
||||
// If we have not started yet, return 1 (because then I don't
|
||||
// have to change the FPS calculation in CoreRerecording.cpp .
|
||||
if (m_StartTime == 0) return 1;
|
||||
|
||||
// Return the final timer time if the timer is stopped
|
||||
if (!m_Running) return (m_LastTime - m_StartTime);
|
||||
|
||||
return (GetTimeMs() - m_StartTime);
|
||||
}
|
||||
|
||||
// Get the formatted time elapsed since the Start()
|
||||
std::string Timer::GetTimeElapsedFormatted() const
|
||||
{
|
||||
// If we have not started yet, return zero
|
||||
if (m_StartTime == 0)
|
||||
return "00:00:00:000";
|
||||
|
||||
// The number of milliseconds since the start.
|
||||
// Use a different value if the timer is stopped.
|
||||
u64 Milliseconds;
|
||||
if (m_Running)
|
||||
Milliseconds = GetTimeMs() - m_StartTime;
|
||||
else
|
||||
Milliseconds = m_LastTime - m_StartTime;
|
||||
// Seconds
|
||||
u32 Seconds = (u32)(Milliseconds / 1000);
|
||||
// Minutes
|
||||
u32 Minutes = Seconds / 60;
|
||||
// Hours
|
||||
u32 Hours = Minutes / 60;
|
||||
|
||||
std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i",
|
||||
Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000);
|
||||
return TmpStr;
|
||||
}
|
||||
|
||||
// Get current time
|
||||
void Timer::IncreaseResolution()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Timer::RestoreResolution()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
timeEndPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the number of seconds since January 1 1970
|
||||
u64 Timer::GetTimeSinceJan1970()
|
||||
{
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
return((u64)ltime);
|
||||
}
|
||||
|
||||
u64 Timer::GetLocalTimeSinceJan1970()
|
||||
{
|
||||
time_t sysTime, tzDiff, tzDST;
|
||||
struct tm * gmTime;
|
||||
|
||||
time(&sysTime);
|
||||
|
||||
// Account for DST where needed
|
||||
gmTime = localtime(&sysTime);
|
||||
if(gmTime->tm_isdst == 1)
|
||||
tzDST = 3600;
|
||||
else
|
||||
tzDST = 0;
|
||||
|
||||
// Lazy way to get local time in sec
|
||||
gmTime = gmtime(&sysTime);
|
||||
tzDiff = sysTime - mktime(gmTime);
|
||||
|
||||
return (u64)(sysTime + tzDiff + tzDST);
|
||||
}
|
||||
|
||||
// Return the current time formatted as Minutes:Seconds:Milliseconds
|
||||
// in the form 00:00:000.
|
||||
void Timer::GetTimeFormatted(char formattedTime[13])
|
||||
{
|
||||
time_t sysTime;
|
||||
struct tm * gmTime;
|
||||
char tmp[13];
|
||||
|
||||
time(&sysTime);
|
||||
gmTime = localtime(&sysTime);
|
||||
|
||||
strftime(tmp, 6, "%M:%S", gmTime);
|
||||
|
||||
// Now tack on the milliseconds
|
||||
#ifdef _WIN32
|
||||
struct timeb tp;
|
||||
(void)::ftime(&tp);
|
||||
sprintf(formattedTime, "%s:%03i", tmp, tp.millitm);
|
||||
#else
|
||||
struct timeval t;
|
||||
(void)gettimeofday(&t, NULL);
|
||||
sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns a timestamp with decimals for precise time comparisons
|
||||
// ----------------
|
||||
double Timer::GetDoubleTime()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct timeb tp;
|
||||
(void)::ftime(&tp);
|
||||
#else
|
||||
struct timeval t;
|
||||
(void)gettimeofday(&t, NULL);
|
||||
#endif
|
||||
// Get continuous timestamp
|
||||
u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970();
|
||||
|
||||
// Remove a few years. We only really want enough seconds to make
|
||||
// sure that we are detecting actual actions, perhaps 60 seconds is
|
||||
// enough really, but I leave a year of seconds anyway, in case the
|
||||
// user's clock is incorrect or something like that.
|
||||
TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60);
|
||||
|
||||
// Make a smaller integer that fits in the double
|
||||
u32 Seconds = (u32)TmpSeconds;
|
||||
#ifdef _WIN32
|
||||
double ms = tp.millitm / 1000.0 / 1000.0;
|
||||
#else
|
||||
double ms = t.tv_usec / 1000000.0;
|
||||
#endif
|
||||
double TmpTime = Seconds + ms;
|
||||
|
||||
return TmpTime;
|
||||
}
|
||||
|
||||
} // Namespace Common
|
|
@ -0,0 +1,61 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
#include "Common.h"
|
||||
#include <string>
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
void Update();
|
||||
|
||||
// The time difference is always returned in milliseconds, regardless of alternative internal representation
|
||||
u64 GetTimeDifference();
|
||||
void AddTimeDifference();
|
||||
void WindBackStartingTime(u64 WindBack);
|
||||
|
||||
static void IncreaseResolution();
|
||||
static void RestoreResolution();
|
||||
static u64 GetTimeSinceJan1970();
|
||||
static u64 GetLocalTimeSinceJan1970();
|
||||
static double GetDoubleTime();
|
||||
|
||||
static void GetTimeFormatted(char formattedTime[13]);
|
||||
std::string GetTimeElapsedFormatted() const;
|
||||
u64 GetTimeElapsed();
|
||||
|
||||
static u32 GetTimeMs();
|
||||
|
||||
private:
|
||||
u64 m_LastTime;
|
||||
u64 m_StartTime;
|
||||
u64 m_frequency;
|
||||
bool m_Running;
|
||||
};
|
||||
|
||||
} // Namespace Common
|
||||
|
||||
#endif // _TIMER_H_
|
|
@ -0,0 +1,52 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "scmrev.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define BUILD_TYPE_STR "Debug "
|
||||
#elif defined DEBUGFAST
|
||||
#define BUILD_TYPE_STR "DebugFast "
|
||||
#else
|
||||
#define BUILD_TYPE_STR ""
|
||||
#endif
|
||||
|
||||
const char *scm_rev_str = "Dolphin "
|
||||
#if !SCM_IS_MASTER
|
||||
"[" SCM_BRANCH_STR "] "
|
||||
#endif
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
BUILD_TYPE_STR SCM_DESC_STR "-ICC";
|
||||
#else
|
||||
BUILD_TYPE_STR SCM_DESC_STR;
|
||||
#endif
|
||||
|
||||
#ifdef _M_X64
|
||||
#define NP_ARCH "x64"
|
||||
#else
|
||||
#define NP_ARCH "x86"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
const char *netplay_dolphin_ver = SCM_DESC_STR " W" NP_ARCH;
|
||||
#elif __APPLE__
|
||||
const char *netplay_dolphin_ver = SCM_DESC_STR " M" NP_ARCH;
|
||||
#else
|
||||
const char *netplay_dolphin_ver = SCM_DESC_STR " L" NP_ARCH;
|
||||
#endif
|
|
@ -0,0 +1,4 @@
|
|||
#define SCM_REV_STR "722480cb2e864ea7dd03427e509470ec09ce6f40"
|
||||
#define SCM_DESC_STR "3.0-589-dirty"
|
||||
#define SCM_BRANCH_STR "master"
|
||||
#define SCM_IS_MASTER 1
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// Common.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
|
@ -0,0 +1,35 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x501
|
||||
#endif
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0500 // Default value is 0x0400
|
||||
#endif
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
//#define _CRT_SECURE_NO_DEPRECATE 1
|
||||
//#define _CRT_NONSTDC_NO_DEPRECATE 1
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <vector>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <SDKDDKVer.h>
|
|
@ -0,0 +1,230 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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 "x64Analyzer.h"
|
||||
|
||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType)
|
||||
{
|
||||
unsigned const char *startCodePtr = codePtr;
|
||||
u8 rex = 0;
|
||||
u8 codeByte = 0;
|
||||
u8 codeByte2 = 0;
|
||||
|
||||
//Check for regular prefix
|
||||
info.operandSize = 4;
|
||||
info.zeroExtend = false;
|
||||
info.signExtend = false;
|
||||
info.hasImmediate = false;
|
||||
info.isMemoryWrite = false;
|
||||
|
||||
int addressSize = 8;
|
||||
u8 modRMbyte = 0;
|
||||
u8 sibByte = 0;
|
||||
bool hasModRM = false;
|
||||
bool hasSIBbyte = false;
|
||||
bool hasDisplacement = false;
|
||||
|
||||
int displacementSize = 0;
|
||||
|
||||
if (*codePtr == 0x66)
|
||||
{
|
||||
info.operandSize = 2;
|
||||
codePtr++;
|
||||
}
|
||||
else if (*codePtr == 0x67)
|
||||
{
|
||||
addressSize = 4;
|
||||
codePtr++;
|
||||
}
|
||||
|
||||
//Check for REX prefix
|
||||
if ((*codePtr & 0xF0) == 0x40)
|
||||
{
|
||||
rex = *codePtr;
|
||||
if (rex & 8) //REX.W
|
||||
{
|
||||
info.operandSize = 8;
|
||||
}
|
||||
codePtr++;
|
||||
}
|
||||
|
||||
codeByte = *codePtr++;
|
||||
|
||||
// Skip two-byte opcode byte
|
||||
bool twoByte = false;
|
||||
if(codeByte == 0x0F)
|
||||
{
|
||||
twoByte = true;
|
||||
codeByte2 = *codePtr++;
|
||||
}
|
||||
|
||||
if (!twoByte)
|
||||
{
|
||||
if ((codeByte & 0xF0) == 0x80 ||
|
||||
((codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02))
|
||||
{
|
||||
modRMbyte = *codePtr++;
|
||||
hasModRM = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D) ||
|
||||
(codeByte2 & 0xF0) == 0x30 ||
|
||||
codeByte2 == 0x77 ||
|
||||
(codeByte2 & 0xF0) == 0x80 ||
|
||||
((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) ||
|
||||
(codeByte2 & 0xF8) == 0xC8)
|
||||
{
|
||||
// No mod R/M byte
|
||||
}
|
||||
else
|
||||
{
|
||||
modRMbyte = *codePtr++;
|
||||
hasModRM = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasModRM)
|
||||
{
|
||||
ModRM mrm(modRMbyte, rex);
|
||||
info.regOperandReg = mrm.reg;
|
||||
if (mrm.mod < 3)
|
||||
{
|
||||
if (mrm.rm == 4)
|
||||
{
|
||||
//SIB byte
|
||||
sibByte = *codePtr++;
|
||||
info.scaledReg = (sibByte >> 3) & 7;
|
||||
info.otherReg = (sibByte & 7);
|
||||
if (rex & 2) info.scaledReg += 8;
|
||||
if (rex & 1) info.otherReg += 8;
|
||||
hasSIBbyte = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//info.scaledReg =
|
||||
}
|
||||
}
|
||||
if (mrm.mod == 1 || mrm.mod == 2)
|
||||
{
|
||||
hasDisplacement = true;
|
||||
if (mrm.mod == 1)
|
||||
displacementSize = 1;
|
||||
else
|
||||
displacementSize = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementSize == 1)
|
||||
info.displacement = (s32)(s8)*codePtr;
|
||||
else
|
||||
info.displacement = *((s32 *)codePtr);
|
||||
codePtr += displacementSize;
|
||||
|
||||
|
||||
if (accessType == 1)
|
||||
{
|
||||
info.isMemoryWrite = true;
|
||||
//Write access
|
||||
switch (codeByte)
|
||||
{
|
||||
case MOVE_8BIT: //move 8-bit immediate
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *codePtr;
|
||||
codePtr++; //move past immediate
|
||||
}
|
||||
break;
|
||||
|
||||
case MOVE_16_32BIT: //move 16 or 32-bit immediate, easiest case for writes
|
||||
{
|
||||
if (info.operandSize == 2)
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *(u16*)codePtr;
|
||||
codePtr += 2;
|
||||
}
|
||||
else if (info.operandSize == 4)
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
}
|
||||
else if (info.operandSize == 8)
|
||||
{
|
||||
info.zeroExtend = true;
|
||||
info.immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_REG_TO_MEM: //move reg to memory
|
||||
break;
|
||||
|
||||
default:
|
||||
PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Memory read
|
||||
|
||||
//mov eax, dword ptr [rax] == 8b 00
|
||||
switch (codeByte)
|
||||
{
|
||||
case 0x0F:
|
||||
switch (codeByte2)
|
||||
{
|
||||
case MOVZX_BYTE: //movzx on byte
|
||||
info.zeroExtend = true;
|
||||
info.operandSize = 1;
|
||||
break;
|
||||
case MOVZX_SHORT: //movzx on short
|
||||
info.zeroExtend = true;
|
||||
info.operandSize = 2;
|
||||
break;
|
||||
case MOVSX_BYTE: //movsx on byte
|
||||
info.signExtend = true;
|
||||
info.operandSize = 1;
|
||||
break;
|
||||
case MOVSX_SHORT: //movsx on short
|
||||
info.signExtend = true;
|
||||
info.operandSize = 2;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 0x8a:
|
||||
if (info.operandSize == 4)
|
||||
{
|
||||
info.operandSize = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
case 0x8b:
|
||||
break; //it's OK don't need to do anything
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
info.instructionSize = (int)(codePtr - startCodePtr);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// 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 or later versions.
|
||||
|
||||
// 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/
|
||||
|
||||
#ifndef _X64ANALYZER_H_
|
||||
#define _X64ANALYZER_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
struct InstructionInfo
|
||||
{
|
||||
int operandSize; //8, 16, 32, 64
|
||||
int instructionSize;
|
||||
int regOperandReg;
|
||||
int otherReg;
|
||||
int scaledReg;
|
||||
bool zeroExtend;
|
||||
bool signExtend;
|
||||
bool hasImmediate;
|
||||
bool isMemoryWrite;
|
||||
u64 immediate;
|
||||
s32 displacement;
|
||||
};
|
||||
|
||||
struct ModRM
|
||||
{
|
||||
int mod, reg, rm;
|
||||
ModRM(u8 modRM, u8 rex)
|
||||
{
|
||||
mod = modRM >> 6;
|
||||
reg = ((modRM >> 3) & 7) | ((rex & 4)?8:0);
|
||||
rm = modRM & 7;
|
||||
}
|
||||
};
|
||||
|
||||
enum{
|
||||
MOVZX_BYTE = 0xB6, //movzx on byte
|
||||
MOVZX_SHORT = 0xB7, //movzx on short
|
||||
MOVSX_BYTE = 0xBE, //movsx on byte
|
||||
MOVSX_SHORT = 0xBF, //movsx on short
|
||||
MOVE_8BIT = 0xC6, //move 8-bit immediate
|
||||
MOVE_16_32BIT = 0xC7, //move 16 or 32-bit immediate
|
||||
MOVE_REG_TO_MEM = 0x89, //move reg to memory
|
||||
};
|
||||
|
||||
enum AccessType{
|
||||
OP_ACCESS_READ = 0,
|
||||
OP_ACCESS_WRITE = 1
|
||||
};
|
||||
|
||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType);
|
||||
|
||||
#endif // _X64ANALYZER_H_
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue